From 5b9073add4435b5c6fa4bb56ae200975706c29ec Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Wed, 19 Mar 2008 09:53:23 +0000 Subject: [PATCH] - Added copyright/license headers to a few files. - Fixed: ACS SetMugShotState needs to check the StatusBar pointer for the proper object type. - Move SBarInfo loading code in d_main.cpp into a static method of DSBarInfo. - Removed dobject.err from the repository. It only contained a list of compiler errors for some very old version of dobject.cpp. - Fixed: A_JumpIfCloser was missing a z-check. - Added Blzut3's SBARINFO update #13: - Split sbarinfo.cpp into two files sbarinfo_display.cpp and sbarinfo_parser.cpp - Rewrote the mug shot system for SBarInfo to allow for scripting and custom states for different means of death. - SBarInfo now loads all SBarInfo lumps instead of just the last one. Clashing status bar definitions will now be cleared before the bar is read. - Fixed: When using transparency with bars the new drawing method (bg over fg) didn't work. In the case that the border value is set to 0 it will revert to the old method (fg over bg). - Fixed: drawbar lost any high res information it was given. - Added: ACS command SetMugShotState(str state) which sets the mug shot state for the activating player. - Added: keepoffsets flag to drawbar. When set the offsets in the fg image will also be applied when displaying the bar. SVN r812 (trunk) --- docs/rh-log.txt | 23 + src/d_main.cpp | 9 +- src/dobject.err | 31 - src/dobjtype.cpp | 34 + src/files.cpp | 60 +- src/g_level.cpp | 1 - src/g_shared/sbarinfo.cpp | 2417 -------------------- src/g_shared/sbarinfo.h | 247 ++ src/g_shared/sbarinfo_display.cpp | 1335 +++++++++++ src/g_shared/sbarinfo_parser.cpp | 1076 +++++++++ src/p_acs.cpp | 11 + src/p_acs.h | 1 + src/p_conversation.cpp | 34 + src/r_defs.h | 9 + src/thingdef/thingdef_codeptr.cpp | 6 +- tools/updaterevision/updaterevision.vcproj | 154 +- wadsrc/sbarinfo.txt | 49 + wadsrc/zdoom.lst | 1 + zdoom.vcproj | 8 +- 19 files changed, 2969 insertions(+), 2537 deletions(-) delete mode 100644 src/dobject.err delete mode 100644 src/g_shared/sbarinfo.cpp create mode 100644 src/g_shared/sbarinfo_display.cpp create mode 100644 src/g_shared/sbarinfo_parser.cpp create mode 100644 wadsrc/sbarinfo.txt diff --git a/docs/rh-log.txt b/docs/rh-log.txt index 93f435838..e1a3574c9 100644 --- a/docs/rh-log.txt +++ b/docs/rh-log.txt @@ -1,3 +1,26 @@ +March 19, 2008 (Changes by Graf Zahl) +- Added copyright/license headers to a few files. +- Fixed: ACS SetMugShotState needs to check the StatusBar pointer for the + proper object type. +- Move SBarInfo loading code in d_main.cpp into a static method of DSBarInfo. +- Removed dobject.err from the repository. It only contained a list of compiler + errors for some very old version of dobject.cpp. +- Fixed: A_JumpIfCloser was missing a z-check. +- Added Blzut3's SBARINFO update #13: +- Split sbarinfo.cpp into two files sbarinfo_display.cpp and sbarinfo_parser.cpp +- Rewrote the mug shot system for SBarInfo to allow for scripting and custom + states for different means of death. +- SBarInfo now loads all SBarInfo lumps instead of just the last one. Clashing + status bar definitions will now be cleared before the bar is read. +- Fixed: When using transparency with bars the new drawing method (bg over fg) + didn't work. In the case that the border value is set to 0 it will revert to + the old method (fg over bg). +- Fixed: drawbar lost any high res information it was given. +- Added: ACS command SetMugShotState(str state) which sets the mug shot state + for the activating player. +- Added: keepoffsets flag to drawbar. When set the offsets in the fg image will + also be applied when displaying the bar. + March 18, 2008 - Fixed the TArray serializer declaration. (Thank you for your warnings, GCC! ;-) diff --git a/src/d_main.cpp b/src/d_main.cpp index 095eed9f3..f6417657d 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -2439,14 +2439,9 @@ void D_DoomMain (void) StartScreen->LoadingStatus ("Init game engine", 0x3f); P_Init (); + //SBarInfo support. - if(Wads.CheckNumForName("SBARINFO") != -1) - { - Printf ("ParseSBarInfo: Loading custom status bar definition.\n"); - SBarInfoScript = new SBarInfo(Wads.GetNumForName("SBARINFO")); //load last SBARINFO lump to avoid clashes - atterm(FreeSBarInfoScript); - } - //end most of the SBarInfo stuff + SBarInfo::Load(); Printf ("D_CheckNetGame: Checking network game status.\n"); StartScreen->LoadingStatus ("Checking network game status.", 0x3f); diff --git a/src/dobject.err b/src/dobject.err deleted file mode 100644 index e92c91c46..000000000 --- a/src/dobject.err +++ /dev/null @@ -1,31 +0,0 @@ -dobject.h(87): Error! E121: col(27) syntax error -dobject.h(87): Note! N393: col(27) included from dthinker.h(38) -dobject.h(87): Note! N393: col(27) included from actor.h(31) -dobject.h(87): Note! N393: col(27) included from dobject.cpp(39) -dobject.h(120): Error! E412: col(36) only member functions can be declared 'const' or 'volatile' -dobject.h(125): Error! E412: col(9) only member functions can be declared 'const' or 'volatile' -dobject.h(128): Error! E204: col(29) 'this' pointer is not defined -dobject.h(130): Error! E386: col(30) attempt to use pointer to undefined class -dobject.h(130): Note! N638: col(30) 'TypeInfo' defined in: dobject.h(83) (col 8) -dobject.h(135): Error! E412: col(9) only member functions can be declared 'const' or 'volatile' -dobject.h(136): Error! E386: col(24) attempt to use pointer to undefined class -dobject.h(136): Note! N638: col(24) 'TypeInfo' defined in: dobject.h(83) (col 8) -dobject.h(136): Error! E204: col(42) 'this' pointer is not defined -dobject.h(148): Error! E121: col(1) syntax error -dobject.h(299): Error! E275: col(9) the second argument of 'operator delete' must be of type 'size_t' -dobject.h(299): Error! E488: col(9) 'operator delete' cannot be overloaded -dobject.h(236): Error! E386: col(24) attempt to use pointer to undefined class -dobject.h(236): Note! N638: col(24) 'TypeInfo' defined in: dobject.h(83) (col 8) -infomacros.h(166): Error! E080: col(2) Actor default lists are only implemented for Visual C++ and GCC -actor.h(310): Error! E029: col(37) symbol 'FindType' has not been declared -actor.h(315): Error! E386: col(27) attempt to use pointer to undefined class -actor.h(315): Note! N638: col(27) 'TypeInfo' defined in: dobject.h(83) (col 8) -actor.h(320): Error! E409: col(1) template argument 'T' is not used in the function argument list -actor.h(320): Note! N392: col(1) 'T' defined in: actor.h(318) (col 16) -actor.h(344): Error! E386: col(52) attempt to use pointer to undefined class -actor.h(344): Note! N638: col(52) 'TypeInfo' defined in: dobject.h(83) (col 8) -actor.h(617): Error! E029: col(47) symbol 'FindType' has not been declared -actor.h(622): Error! E409: col(1) template argument 'T' is not used in the function argument list -actor.h(622): Note! N392: col(1) 'T' defined in: actor.h(620) (col 16) -d_player.h(31): Error! E059: col(10) unable to open 'a_artifacts.h' -p_pspr.h(87): Error! E133: col(43) too many errors: compilation aborted diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 070429c1f..53c8fa755 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -1,3 +1,37 @@ +/* +** dobjtype.cpp +** Implements the type information class +** +**--------------------------------------------------------------------------- +** Copyright 1998-2008 Randy Heit +** 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 "dobject.h" #include "i_system.h" #include "actor.h" diff --git a/src/files.cpp b/src/files.cpp index dede449d6..2acdd16c0 100644 --- a/src/files.cpp +++ b/src/files.cpp @@ -1,7 +1,50 @@ +/* +** files.cpp +** Implements classes for reading from files or memory blocks +** +**--------------------------------------------------------------------------- +** Copyright 1998-2008 Randy Heit +** Copyright 2005-2008 Christoph Oelckers +** 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 "files.h" #include "i_system.h" #include "templates.h" +//========================================================================== +// +// FileReader +// +// reads data from an uncompressed file or part of it +// +//========================================================================== + FileReader::FileReader () : File(NULL), Length(0), CloseOnDestruct(false) { @@ -99,7 +142,14 @@ long FileReader::CalcFileLen() const return endpos; } -// Now for the zlib wrapper ------------------------------------------------- +//========================================================================== +// +// FileReaderZ +// +// The zlib wrapper +// reads data from a ZLib compressed stream +// +//========================================================================== FileReaderZ::FileReaderZ (FileReader &file, bool zip) : File(file), SawEOF(false) @@ -166,6 +216,14 @@ void FileReaderZ::FillBuffer () Stream.avail_in = numread; } +//========================================================================== +// +// MemoryReader +// +// reads data from a block of memory +// +//========================================================================== + MemoryReader::MemoryReader (const char *buffer, long length) { bufptr=buffer; diff --git a/src/g_level.cpp b/src/g_level.cpp index 8bc495004..a6a6a8b04 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -74,7 +74,6 @@ #include "vectors.h" #include "sbarinfo.h" #include "r_translate.h" -#include "sbarinfo.h" #include "gi.h" diff --git a/src/g_shared/sbarinfo.cpp b/src/g_shared/sbarinfo.cpp deleted file mode 100644 index 31e38ae42..000000000 --- a/src/g_shared/sbarinfo.cpp +++ /dev/null @@ -1,2417 +0,0 @@ -#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 "sc_man.h" -#include "gi.h" -#include "r_translate.h" -#include "r_main.h" - -static FRandom pr_chainwiggle; //use the same method of chain wiggling as heretic. - -#define ST_FACETIME (TICRATE/2) -#define ST_PAINTIME (TICRATE) -#define ST_GRINTIME (TICRATE*2) -#define ST_RAMPAGETIME (TICRATE*2) -#define ST_XDTHTIME (TICRATE*(3/2)) -#define ST_NUMFACES 82 //9 levels with 8 faces each, 3 god, 1 death, 6 xdeath -#define ARTIFLASH_OFFSET (invBarOffset+6) - -EXTERN_CVAR(Int, fraglimit) -EXTERN_CVAR(Int, screenblocks) - -SBarInfo *SBarInfoScript; - -enum //statusbar flags -{ - STATUSBARFLAG_FORCESCALED = 1, -}; - -enum //gametype flags -{ - GAMETYPE_SINGLEPLAYER = 1, - GAMETYPE_COOPERATIVE = 2, - GAMETYPE_DEATHMATCH = 4, - GAMETYPE_TEAMGAME = 8, -}; - -enum //drawimage flags -{ - DRAWIMAGE_PLAYERICON = 1, - DRAWIMAGE_AMMO1 = 2, - DRAWIMAGE_AMMO2 = 4, - DRAWIMAGE_INVENTORYICON = 8, - DRAWIMAGE_TRANSLATABLE = 16, - DRAWIMAGE_WEAPONSLOT = 32, - DRAWIMAGE_SWITCHABLE_AND = 64, - DRAWIMAGE_INVULNERABILITY = 128, - DRAWIMAGE_OFFSET_CENTER = 256, - DRAWIMAGE_ARMOR = 512, - DRAWIMAGE_WEAPONICON = 1024, -}; - -enum //drawnumber flags -{ - DRAWNUMBER_HEALTH = 1, - DRAWNUMBER_ARMOR = 2, - DRAWNUMBER_AMMO1 = 4, - DRAWNUMBER_AMMO2 = 8, - DRAWNUMBER_AMMO = 16, - DRAWNUMBER_AMMOCAPACITY = 32, - DRAWNUMBER_FRAGS = 64, - DRAWNUMBER_INVENTORY = 128, - DRAWNUMBER_KILLS = 256, - DRAWNUMBER_MONSTERS = 512, - DRAWNUMBER_ITEMS = 1024, - DRAWNUMBER_TOTALITEMS = 2048, - DRAWNUMBER_SECRETS = 4096, - DRAWNUMBER_TOTALSECRETS = 8192, - DRAWNUMBER_ARMORCLASS = 16384, -}; - -enum //drawbar flags (will go into special2) -{ - DRAWBAR_HORIZONTAL = 1, - DRAWBAR_REVERSE = 2, - DRAWBAR_COMPAREDEFAULTS = 4, -}; - -enum //drawselectedinventory flags -{ - DRAWSELECTEDINVENTORY_ALTERNATEONEMPTY = 1, - DRAWSELECTEDINVENTORY_ARTIFLASH = 2, - DRAWSELECTEDINVENTORY_ALWAYSSHOWCOUNTER = 4, -}; - -enum //drawinventorybar flags -{ - DRAWINVENTORYBAR_ALWAYSSHOW = 1, - DRAWINVENTORYBAR_NOARTIBOX = 2, - DRAWINVENTORYBAR_NOARROWS = 4, - DRAWINVENTORYBAR_ALWAYSSHOWCOUNTER = 8, -}; - -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 = 1, - DRAWMUGSHOT_ANIMATEDGODMODE = 2, -}; - -enum //drawkeybar flags -{ - DRAWKEYBAR_VERTICAL = 1, -}; - -enum //event flags -{ - SBARINFOEVENT_NOT = 1, - SBARINFOEVENT_OR = 2, - SBARINFOEVENT_AND = 4, -}; - -static const char *SBarInfoTopLevel[] = -{ - "base", - "height", - "interpolatehealth", - "interpolatearmor", - "completeborder", - "statusbar", - NULL -}; -enum -{ - SBARINFO_BASE, - SBARINFO_HEIGHT, - SBARINFO_INTERPOLATEHEALTH, - SBARINFO_INTERPOLATEARMOR, - SBARINFO_COMPLETEBORDER, - SBARINFO_STATUSBAR, -}; - -static const char *StatusBars[] = -{ - "none", - "fullscreen", - "normal", - "automap", - "inventory", - "inventoryfullscreen", - NULL -}; -enum -{ - STBAR_NONE, - STBAR_FULLSCREEN, - STBAR_NORMAL, - STBAR_AUTOMAP, - STBAR_INVENTORY, - STBAR_INVENTORYFULLSCREEN, -}; - -static const char *SBarInfoRoutineLevel[] = -{ - "drawimage", - "drawnumber", - "drawswitchableimage", - "drawmugshot", - "drawselectedinventory", - "drawinventorybar", - "drawbar", - "drawgem", - "drawshader", - "drawstring", - "drawkeybar", - "gamemode", - "playerclass", - "weaponammo", //event - NULL -}; -enum -{ - 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_WEAPONAMMO, -}; - -void FreeSBarInfoScript() -{ - if (SBarInfoScript != NULL) - { - delete SBarInfoScript; - SBarInfoScript = NULL; - } -} - -//SBarInfo Script Reader -void SBarInfo::ParseSBarInfo(int lump) -{ - FScanner sc(lump, Wads.GetLumpFullName(lump)); - gameType = GAME_Any; - 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); //zip/pk3 - //Do a normal wad lookup. - if (lump == -1 && sc.StringLen <= 8 && !strchr(sc.String, '/')) - lump = Wads.CheckNumForName(sc.String); - if (lump == -1) - sc.ScriptError("Lump '%s' not found", sc.String); - ParseSBarInfo(lump); - continue; - } - switch(sc.MustMatchString(SBarInfoTopLevel)) - { - case SBARINFO_BASE: - if(!sc.CheckToken(TK_None)) - sc.MustGetToken(TK_Identifier); - if(sc.Compare("Doom")) - gameType = GAME_Doom; - 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_STATUSBAR: - { - int barNum = 0; - if(!sc.CheckToken(TK_None)) - { - sc.MustGetToken(TK_Identifier); - barNum = sc.MustMatchString(StatusBars); - } - while(sc.CheckToken(',')) - { - sc.MustGetToken(TK_Identifier); - if(sc.Compare("forcescaled")) - { - this->huds[barNum].forceScaled = true; - } - else - { - sc.ScriptError("Unkown flag '%s'.", sc.String); - } - } - sc.MustGetToken('{'); - if(barNum == STBAR_AUTOMAP) - { - automapbar = true; - } - ParseSBarInfoBlock(sc, this->huds[barNum]); - 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 - { - 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; - 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("translatable")) - { - cmd.flags += DRAWIMAGE_TRANSLATABLE; - getImage = true; - } - else - { - 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 = ((AInventory *)GetDefaultByType(item))->Icon; - } - } - if(getImage) - { - sc.MustGetToken(TK_StringConst); - cmd.sprite = newImage(sc.String); - } - sc.MustGetToken(','); - this->getCoordinates(sc, cmd); - if(sc.CheckToken(',')) - { - sc.MustGetToken(TK_Identifier); - if(sc.Compare("center")) - cmd.flags += DRAWIMAGE_OFFSET_CENTER; - else - sc.ScriptError("Expected 'center' got '%s' instead.", 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 - { - cmd.flags = DRAWNUMBER_INVENTORY; - sc.MustGetToken(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 ammo - { - sc.ScriptError("'%s' is not a type of inventory item.", sc.String); - } - } - sc.MustGetToken(','); - } - this->getCoordinates(sc, cmd); - 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: - sc.MustGetToken(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 - sc.ScriptError("Unknown flag '%s'.", sc.String); - if(!sc.CheckToken('|')) - sc.MustGetToken(','); - } - this->getCoordinates(sc, cmd); - 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 - { - 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(','); - } - sc.MustGetToken(TK_IntConst); - cmd.x = sc.Number; - sc.MustGetToken(','); - sc.MustGetToken(TK_IntConst); - cmd.y = sc.Number - (200 - this->height); - cmd.special2 = cmd.x + 30; - cmd.special3 = cmd.y + 24; - cmd.translation = CR_GOLD; - if(sc.CheckToken(',')) //more font information - { - sc.MustGetToken(TK_IntConst); - cmd.special2 = sc.Number; - sc.MustGetToken(','); - sc.MustGetToken(TK_IntConst); - cmd.special3 = sc.Number - (200 - this->height); - 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('{'); - this->ParseSBarInfoBlock(sc, cmd.subBlock); - } - else - { - sc.MustGetToken(';'); - } - break; - } - case SBARINFO_DRAWINVENTORYBAR: - sc.MustGetToken(TK_Identifier); - if(sc.Compare("Heretic")) - { - cmd.special = GAME_Heretic; - } - if(sc.Compare("Doom") || sc.Compare("Heretic")) - { - 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 - { - 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); - } - else - { - sc.ScriptError("Unkown style '%s'.", sc.String); - } - sc.MustGetToken(','); - this->getCoordinates(sc, cmd); - cmd.special2 = cmd.x + 26; - cmd.special3 = cmd.y + 22; - cmd.translation = CR_GOLD; - if(sc.CheckToken(',')) //more font information - { - sc.MustGetToken(TK_IntConst); - cmd.special2 = sc.Number; - sc.MustGetToken(','); - sc.MustGetToken(TK_IntConst); - cmd.special3 = sc.Number - (200 - this->height); - 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.sprite = newImage(sc.String); - 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 - { - 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)) //must be a kind of ammo - { - 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(','); - if(sc.CheckToken(TK_Identifier)) - { - if(!sc.Compare("reverse")) - { - sc.ScriptError("Exspected 'reverse', got '%s' instead.", sc.String); - } - cmd.special2 += DRAWBAR_REVERSE; - sc.MustGetToken(','); - } - this->getCoordinates(sc, cmd); - 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.sprite = newImage(sc.String); - 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, cmd); - 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, cmd); - 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, cmd); - 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(','); - sc.MustGetToken(TK_IntConst); - cmd.special = sc.Number; - sc.MustGetToken(','); - this->getCoordinates(sc, cmd); - 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 - sc.ScriptError("Unknown gamemode: %s", sc.String); - if(sc.CheckToken('{')) - break; - sc.MustGetToken(','); - } - 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: - 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('{'); - this->ParseSBarInfoBlock(sc, cmd.subBlock); - break; - } - block.commands.Push(cmd); - } - sc.MustGetToken('}'); -} - -void SBarInfo::getCoordinates(FScanner &sc, SBarInfoCommand &cmd) -{ - bool negative = false; - negative = sc.CheckToken('-'); - sc.MustGetToken(TK_IntConst); - cmd.x = negative ? -sc.Number : sc.Number; - sc.MustGetToken(','); - negative = sc.CheckToken('-'); - sc.MustGetToken(TK_IntConst); - cmd.y = (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(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, 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; - interpolationSpeed = 8; - armorInterpolationSpeed = 8; - height = 0; -} - -SBarInfo::~SBarInfo() -{ - for (size_t i = 0; i < countof(huds); ++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; -} - -enum -{ - ST_FACENORMALRIGHT, - ST_FACENORMAL, - ST_FACENORMALLEFT, - ST_FACEPAINRIGHT, - ST_FACEPAINLEFT, - ST_FACEOUCH, - ST_FACEGRIN, - ST_FACEPAIN, - ST_FACEGOD = 72, - ST_FACEGODRIGHT = 73, //switch the roles of 0 and 1 because 0 is taken by Doom. - ST_FACEGODLEFT = 74, - ST_FACEDEAD = 75, - ST_FACEXDEAD = 76, -}; - -enum -{ - imgARTIBOX, - imgSELECTBOX, - imgINVLFGEM1, - imgINVLFGEM2, - imgINVRTGEM1, - imgINVRTGEM2, -}; - -//Used for shading -class FBarShader : public FTexture -{ -public: - 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 : 1; - 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) * 256; - } - - const BYTE *GetPixels() - { - return Pixels; - } - - void Unload() - { - } - -private: - BYTE Pixels[512]; - Span DummySpan[2]; -}; - -SBarInfoCommand::SBarInfoCommand() //sets the default values for more predicable behavior -{ - type = 0; - special = 0; - special2 = 0; - special3 = 0; - special4 = 0; - flags = 0; - x = 0; - y = 0; - value = 0; - sprite = 0; - translation = CR_UNTRANSLATED; - translation2 = CR_UNTRANSLATED; - translation3 = CR_UNTRANSLATED; - font = V_GetFont("CONFONT"); -} - -SBarInfoCommand::~SBarInfoCommand() -{ -} - -SBarInfoBlock::SBarInfoBlock() -{ - forceScaled = false; -} - -//SBarInfo Display -class DSBarInfo : public DBaseStatusBar -{ - DECLARE_CLASS(DSBarInfo, DBaseStatusBar) -public: - DSBarInfo () : DBaseStatusBar (SBarInfoScript->height), - shader_horz_normal(false, false), - shader_horz_reverse(false, true), - shader_vert_normal(true, false), - shader_vert_reverse(true, true) - { - static const char *InventoryBarLumps[] = - { - "ARTIBOX", "SELECTBO", "INVGEML1", - "INVGEML2", "INVGEMR1", "INVGEMR2", - "USEARTIA", "USEARTIB", "USEARTIC", "USEARTID", - }; - TArray patchnames; - patchnames.Resize(SBarInfoScript->Images.Size()+10); - unsigned int i = 0; - for(i = 0;i < SBarInfoScript->Images.Size();i++) - { - patchnames[i] = SBarInfoScript->Images[i]; - } - for(i = 0;i < 10;i++) - { - patchnames[i+SBarInfoScript->Images.Size()] = InventoryBarLumps[i]; - } - invBarOffset = SBarInfoScript->Images.Size(); - Images.Init(&patchnames[0], patchnames.Size()); - drawingFont = V_GetFont("ConFont"); - faceTimer = ST_FACETIME; - rampageTimer = 0; - faceIndex = 0; - oldHealth = 0; - oldArmor = 0; - mugshotHealth = -1; - lastPrefix = ""; - weaponGrin = false; - chainWiggle = 0; - artiflash = 4; - } - - ~DSBarInfo () - { - Images.Uninit(); - Faces.Uninit(); - } - - void Draw (EHudState state) - { - DBaseStatusBar::Draw(state); - int hud = 2; - if(state == HUD_StatusBar) - { - if(SBarInfoScript->completeBorder) //Fill the statusbar with the border before we draw. - { - FTexture *b = TexMan[gameinfo.border->b]; - R_DrawBorder(viewwindowx, viewwindowy + realviewheight + b->GetHeight(), viewwindowx + realviewwidth, SCREENHEIGHT); - if(screenblocks == 10) - screen->FlatFill(viewwindowx, viewwindowy + realviewheight, viewwindowx + realviewwidth, viewwindowy + realviewheight + b->GetHeight(), b, true); - } - if(SBarInfoScript->automapbar && automapactive) - { - hud = 3; - } - else - { - hud = 2; - } - } - else if(state == HUD_Fullscreen) - { - hud = 1; - } - else - { - hud = 0; - } - if(SBarInfoScript->huds[hud].forceScaled) //scale the statusbar - { - SetScaled(true); - setsizeneeded = true; - } - doCommands(SBarInfoScript->huds[hud]); - if(CPlayer->inventorytics > 0 && !(level.flags & LEVEL_NOINVENTORYBAR)) - { - if(state == HUD_StatusBar) - doCommands(SBarInfoScript->huds[4]); - else if(state == HUD_Fullscreen) - doCommands(SBarInfoScript->huds[5]); - } - } - - void NewGame () - { - if (CPlayer != NULL) - { - AttachToPlayer (CPlayer); - } - } - - void AttachToPlayer (player_t *player) - { - player_t *oldplayer = CPlayer; - DBaseStatusBar::AttachToPlayer(player); - if (oldplayer != CPlayer) - { - SetFace(&skins[CPlayer->userinfo.skin], "STF"); - } - } - - void Tick () - { - DBaseStatusBar::Tick(); - if(level.time & 1) - chainWiggle = pr_chainwiggle() & 1; - getNewFace(M_Random()); - if(!SBarInfoScript->interpolateHealth) - { - oldHealth = CPlayer->health; - } - else - { - if(oldHealth > CPlayer->health) - { - oldHealth -= clamp((oldHealth - CPlayer->health) >> 2, 1, SBarInfoScript->interpolationSpeed); - } - else if(oldHealth < CPlayer->health) - { - oldHealth += clamp((CPlayer->health - oldHealth) >> 2, 1, SBarInfoScript->interpolationSpeed); - } - } - AInventory *armor = CPlayer->mo->FindInventory(); - if(armor == NULL) - { - oldArmor = 0; - } - else - { - if(!SBarInfoScript->interpolateArmor) - { - oldArmor = armor->Amount; - } - else - { - if(oldArmor > armor->Amount) - { - oldArmor -= clamp((oldArmor - armor->Amount) >> 2, 1, SBarInfoScript->armorInterpolationSpeed); - } - else if(oldArmor < armor->Amount) - { - oldArmor += clamp((armor->Amount - oldArmor) >> 2, 1, SBarInfoScript->armorInterpolationSpeed); - } - } - } - if(artiflash) - { - artiflash--; - } - } - - void SetFace (void *skn) - { - SetFace((FPlayerSkin *)skn, "STF"); - } - - void ReceivedWeapon (AWeapon *weapon) - { - weaponGrin = true; - } - - void FlashItem(const PClass *itemtype) - { - artiflash = 4; - } -private: - //code from doom_sbar.cpp but it should do fine. - void SetFace (FPlayerSkin *skin, const char* defPrefix) - { - oldSkin = skin; - const char *nameptrs[ST_NUMFACES]; - char names[ST_NUMFACES][9]; - char prefix[4]; - int i, j; - int namespc; - int facenum; - - for (i = 0; i < ST_NUMFACES; i++) - { - nameptrs[i] = names[i]; - } - - if (skin->face[0] != 0) - { - prefix[0] = skin->face[0]; - prefix[1] = skin->face[1]; - prefix[2] = skin->face[2]; - prefix[3] = 0; - namespc = skin->namespc; - } - else - { - prefix[0] = defPrefix[0]; - prefix[1] = defPrefix[1]; - prefix[2] = defPrefix[2]; - prefix[3] = 0; - namespc = ns_global; - } - if(stricmp(prefix, lastPrefix) == 0) - { - return; - } - lastPrefix = prefix; - - facenum = 0; - - for (i = 0; i < 9; i++) //levels - { - for (j = 0; j < 3; j++) - { - sprintf (names[facenum++], "%sST%d%d", prefix, i, j); - } - sprintf (names[facenum++], "%sTR%d0", prefix, i); // turn right - sprintf (names[facenum++], "%sTL%d0", prefix, i); // turn left - sprintf (names[facenum++], "%sOUCH%d", prefix, i); // ouch! - sprintf (names[facenum++], "%sEVL%d", prefix, i); // evil grin ;) - sprintf (names[facenum++], "%sKILL%d", prefix, i); // pissed off - } - for (i = 0; i < 3; i++) - sprintf (names[facenum++], "%sGOD%d", prefix, i); - sprintf (names[facenum++], "%sDEAD0", prefix); - for(i = 0;i < 6;i++) //xdeath - { - sprintf (names[facenum++], "%sXDTH%d", prefix, i); - } - - Faces.Uninit (); - Faces.Init (nameptrs, ST_NUMFACES, namespc); - - faceIndex = ST_FACENORMAL; - faceTimer = 0; - } - void doCommands(SBarInfoBlock &block) - { - //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(SBarInfoScript->interpolateHealth) - { - health = oldHealth; - } - if(SBarInfoScript->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 - { - 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 < MAX_WEAPONS_PER_SLOT; i++) - { - const PClass *weap = LocalWeapons.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 //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, cmd.flags); - else if(cmd.special2 != -1 && drawAlt == 2) - DrawGraphic(Images[cmd.special2], cmd.x, cmd.y, cmd.flags); - else if(cmd.special3 != -1 && drawAlt == 3) - DrawGraphic(Images[cmd.special3], cmd.x, cmd.y, cmd.flags); - break; - } - } - case SBARINFO_DRAWIMAGE: - if((cmd.flags & DRAWIMAGE_PLAYERICON)) - DrawGraphic(TexMan[CPlayer->mo->ScoreIcon], cmd.x, cmd.y, cmd.flags); - else if((cmd.flags & DRAWIMAGE_AMMO1)) - { - if(ammo1 != NULL) - DrawGraphic(TexMan[ammo1->Icon], cmd.x, cmd.y, cmd.flags); - } - else if((cmd.flags & DRAWIMAGE_AMMO2)) - { - if(ammo2 != NULL) - DrawGraphic(TexMan[ammo2->Icon], cmd.x, cmd.y, cmd.flags); - } - else if((cmd.flags & DRAWIMAGE_ARMOR)) - { - if(armor != NULL && armor->Amount != 0) - DrawGraphic(TexMan(armor->Icon), cmd.x, cmd.y, cmd.flags); - } - else if((cmd.flags & DRAWIMAGE_WEAPONICON)) - { - AWeapon *weapon = CPlayer->ReadyWeapon; - if(weapon != NULL && weapon->Icon > 0) - { - DrawGraphic(TexMan[weapon->Icon], cmd.x, cmd.y, cmd.flags); - } - } - else if((cmd.flags & DRAWIMAGE_INVENTORYICON)) - { - DrawGraphic(TexMan[cmd.sprite], cmd.x, cmd.y, cmd.flags); - } - else - { - DrawGraphic(Images[cmd.sprite], cmd.x, cmd.y, cmd.flags); - } - break; - case SBARINFO_DRAWNUMBER: - if(drawingFont != cmd.font) - { - drawingFont = cmd.font; - } - if(cmd.flags == DRAWNUMBER_HEALTH) - { - cmd.value = health; - if(cmd.value < 0) //health shouldn't display negatives - { - cmd.value = 0; - } - } - else if(cmd.flags == DRAWNUMBER_ARMOR) - { - cmd.value = armorAmount; - } - else if(cmd.flags == DRAWNUMBER_AMMO1) - { - cmd.value = ammocount1; - if(ammo1 == NULL) //no ammo, do not draw - { - continue; - } - } - else if(cmd.flags == DRAWNUMBER_AMMO2) - { - cmd.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) - { - cmd.value = item->Amount; - } - else - { - cmd.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) - { - cmd.value = item->MaxAmount; - } - else - { - cmd.value = ((AInventory *)GetDefaultByType(ammo))->MaxAmount; - } - } - else if(cmd.flags == DRAWNUMBER_FRAGS) - cmd.value = CPlayer->fragcount; - else if(cmd.flags == DRAWNUMBER_KILLS) - cmd.value = level.killed_monsters; - else if(cmd.flags == DRAWNUMBER_MONSTERS) - cmd.value = level.total_monsters; - else if(cmd.flags == DRAWNUMBER_ITEMS) - cmd.value = level.found_items; - else if(cmd.flags == DRAWNUMBER_TOTALITEMS) - cmd.value = level.total_items; - else if(cmd.flags == DRAWNUMBER_SECRETS) - cmd.value = level.found_secrets; - else if(cmd.flags == DRAWNUMBER_TOTALSECRETS) - cmd.value = level.total_secrets; - else if(cmd.flags == DRAWNUMBER_ARMORCLASS) - { - AHexenArmor *harmor = CPlayer->mo->FindInventory(); - if(harmor != NULL) - { - cmd.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) - { - cmd.value += armor->SavePercent; - } - cmd.value /= (5*FRACUNIT); - } - else if(cmd.flags == DRAWNUMBER_INVENTORY) - { - AInventory* item = CPlayer->mo->FindInventory(PClass::FindClass(cmd.string[0])); - if(item != NULL) - { - cmd.value = item->Amount; - } - else - { - cmd.value = 0; - } - } - if(cmd.special3 != -1 && cmd.value <= cmd.special3) //low - DrawNumber(cmd.value, cmd.special, cmd.x, cmd.y, cmd.translation2, cmd.special2); - else if(cmd.special4 != -1 && cmd.value >= cmd.special4) //high - DrawNumber(cmd.value, cmd.special, cmd.x, cmd.y, cmd.translation3, cmd.special2); - else - DrawNumber(cmd.value, cmd.special, cmd.x, cmd.y, cmd.translation, cmd.special2); - break; - case SBARINFO_DRAWMUGSHOT: - { - bool xdth = false; - bool animatedgodmode = false; - if(cmd.flags & DRAWMUGSHOT_XDEATHFACE) - xdth = true; - if(cmd.flags & DRAWMUGSHOT_ANIMATEDGODMODE) - animatedgodmode = true; - SetFace(oldSkin, cmd.string[0].GetChars()); - DrawFace(cmd.special, xdth, animatedgodmode, cmd.x, cmd.y); - break; - } - case SBARINFO_DRAWSELECTEDINVENTORY: - if(CPlayer->mo->InvSel != NULL && !(level.flags & LEVEL_NOINVENTORYBAR)) - { - if((cmd.flags & DRAWSELECTEDINVENTORY_ARTIFLASH) && artiflash) - { - DrawDimImage(Images[ARTIFLASH_OFFSET+(4-artiflash)], cmd.x, cmd.y, CPlayer->mo->InvSel->Amount <= 0); - } - else - { - DrawDimImage(TexMan(CPlayer->mo->InvSel->Icon), cmd.x, cmd.y, CPlayer->mo->InvSel->Amount <= 0); - } - if((cmd.flags & DRAWSELECTEDINVENTORY_ALWAYSSHOWCOUNTER) || CPlayer->mo->InvSel->Amount != 1) - { - if(drawingFont != cmd.font) - { - drawingFont = cmd.font; - } - DrawNumber(CPlayer->mo->InvSel->Amount, 3, cmd.special2, cmd.special3, cmd.translation, cmd.special4); - } - } - else if((cmd.flags & DRAWSELECTEDINVENTORY_ALTERNATEONEMPTY)) - { - doCommands(cmd.subBlock); - } - break; - case SBARINFO_DRAWINVENTORYBAR: - { - bool alwaysshow = false; - bool artibox = true; - bool noarrows = false; - bool alwaysshowcounter = false; - 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(drawingFont != cmd.font) - { - drawingFont = cmd.font; - } - DrawInventoryBar(cmd.special, cmd.value, cmd.x, cmd.y, alwaysshow, cmd.special2, cmd.special3, cmd.translation, artibox, noarrows, alwaysshowcounter); - break; - } - case SBARINFO_DRAWBAR: - { - if(cmd.sprite == -1 || Images[cmd.sprite] == 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->GetDefault()->health; - } - } - 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; - } - } - 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(max == 0 && value <= 0) - { - value = FRACUNIT; - } - else - { - value = 0; - } - assert(Images[cmd.sprite] != NULL); - - FTexture *fg = Images[cmd.sprite]; - FTexture *bg = (cmd.special != -1) ? Images[cmd.special] : NULL; - int x, y, w, h; - int cx, cy, cw, ch, cr, cb; - - // Calc real screen coordinates for bar - x = cmd.x + ST_X; - y = cmd.y + ST_Y; - w = fg->GetWidth(); - h = fg->GetHeight(); - if (Scaled) - { - screen->VirtualToRealCoordsInt(x, y, w, h, 320, 200, true); - } - - //Draw the whole foreground - screen->DrawTexture(fg, x, y, - DTA_DestWidth, w, - DTA_DestHeight, h, - TAG_DONE); - - // Calc clipping rect for background - cx = cmd.x + ST_X + cmd.special3; - cy = cmd.y + ST_Y + cmd.special3; - cw = fg->GetWidth() - cmd.special3 * 2; - ch = fg->GetHeight() - cmd.special3 * 2; - if (Scaled) - { - screen->VirtualToRealCoordsInt(cx, cy, cw, ch, 320, 200, true); - } - if (horizontal) - { - if (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 (reverse) - { // bottom to top - cb = cy + ch; - cy += FixedMul(ch, FRACUNIT - value); - } - else - { // top to bottom - cb = cy + FixedMul(ch, value); - } - cr = cx + cw; - } - - // Draw background - if (bg != NULL && bg->GetWidth() == fg->GetWidth() && bg->GetHeight() == fg->GetHeight()) - { - screen->DrawTexture(bg, x, y, - DTA_DestWidth, w, - DTA_DestHeight, h, - DTA_ClipLeft, cx, - DTA_ClipTop, cy, - DTA_ClipRight, cr, - DTA_ClipBottom, cb, - TAG_DONE); - } - else - { - screen->Clear(cx, cy, cr, cb, GPalette.BlackIndex, 0); - } - break; - } - case SBARINFO_DRAWGEM: - { - int value = (cmd.flags & DRAWGEM_ARMOR) ? armorAmount : health; - int max = 100; - 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.sprite], value, cmd.x, cmd.y, 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); - screen->DrawTexture (shaders[(vertical << 1) + reverse], ST_X+cmd.x, ST_Y+cmd.y, - DTA_DestWidth, cmd.special, - DTA_DestHeight, cmd.special2, - DTA_Bottom320x200, Scaled, - DTA_AlphaChannel, true, - DTA_FillColor, 0, - 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, cmd.translation); - break; - case SBARINFO_DRAWKEYBAR: - { - bool vertical = !!(cmd.flags & DRAWKEYBAR_VERTICAL); - AInventory *item = CPlayer->mo->Inventory; - if(item == NULL) - break; - for(int i = 0;i < cmd.value;i++) - { - while(item->Icon <= 0 || item->GetClass() == RUNTIME_CLASS(AKey) || !item->IsKindOf(RUNTIME_CLASS(AKey))) - { - item = item->Inventory; - if(item == NULL) - goto FinishDrawKeyBar; - } - if(!vertical) - DrawImage(TexMan[item->Icon], cmd.x+(cmd.special*i), cmd.y); - else - DrawImage(TexMan[item->Icon], cmd.x, cmd.y+(cmd.special*i)); - 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); - } - break; - case SBARINFO_PLAYERCLASS: - { - int spawnClass = CPlayer->cls->ClassIndex; - if(cmd.special == spawnClass || cmd.special2 == spawnClass || cmd.special3 == spawnClass) - { - doCommands(cmd.subBlock); - } - 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); - 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); - } - else if(cmd.flags & SBARINFOEVENT_NOT) - { - doCommands(cmd.subBlock); - } - } - 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); - } - else if(cmd.flags & SBARINFOEVENT_NOT) - { - doCommands(cmd.subBlock); - } - } - } - break; - } - } - } - - //draws an image with the specified flags - void DrawGraphic(FTexture* texture, int x, int y, int flags) - { - if((flags & DRAWIMAGE_OFFSET_CENTER)) - { - x -= (texture->GetWidth()/2)-texture->LeftOffset; - y -= (texture->GetHeight()/2)-texture->TopOffset; - } - if((flags & DRAWIMAGE_TRANSLATABLE)) - DrawImage(texture, x, y, getTranslation()); - else - DrawImage(texture, x, y); - } - - void DrawString(const char* str, int x, int y, EColorRange translation, int spacing=0) - { - x += spacing; - while(*str != '\0') - { - if(*str == ' ') - { - x += drawingFont->GetSpaceWidth(); - str++; - continue; - } - int width = drawingFont->GetCharWidth((int) *str); - FTexture* character = drawingFont->GetChar((int) *str, &width); - if(character == NULL) //missing character. - { - str++; - continue; - } - x += (character->LeftOffset+1); //ignore x offsets since we adapt to character size - DrawImage(character, x, y, drawingFont->GetColorTranslation(translation)); - x += width + spacing - (character->LeftOffset+1); - str++; - } - } - - //draws the specified number up to len digits - void DrawNumber(int num, int len, int x, int y, EColorRange translation, int spacing=0) - { - FString value; - int maxval = (int) ceil(pow(10., len))-1; - num = clamp(num, -maxval, maxval); - value.Format("%d", num); - x -= int(drawingFont->StringWidth(value)+(spacing * value.Len())); - DrawString(value, x, y, translation, spacing); - } - - //draws the mug shot - void DrawFace(int accuracy, bool xdth, bool animatedgodmode, int x, int y) - { - if(CPlayer->health > 0) - { - if(faceIndex == ST_FACEGOD || faceIndex == ST_FACEGODLEFT || faceIndex == ST_FACEGODRIGHT) //nothing fancy to do here - { - if(animatedgodmode) - DrawImage(Faces[faceIndex], x, y); - else - DrawImage(Faces[ST_FACEGOD], x, y); - } - else - { - int level = 0; - for(level = 0;CPlayer->health < (accuracy-level-1)*(CPlayer->mo->GetMaxHealth()/accuracy);level++); - int face = faceIndex + level*8; - DrawImage(Faces[face], x, y); - } - } - else //dead - { - if(!xdth || !(CPlayer->cheats & CF_EXTREMELYDEAD)) - { - DrawImage(Faces[ST_FACEDEAD], x, y); - } - else - { - if(faceIndex != ST_FACEXDEAD+5 && faceIndex >= ST_FACEXDEAD) //animate - { - if(faceTimer == 0) - { - faceIndex++; - faceTimer = ST_XDTHTIME; - } - faceTimer--; - } - else if(faceIndex < ST_FACEXDEAD) //set to xdeath - { - faceIndex = ST_FACEXDEAD; - faceTimer = ST_XDTHTIME; - } - DrawImage(Faces[faceIndex], x, y); - } - } - } - - //Does some face drawing logic. - void getNewFace(int number) - { - int i; - angle_t badguyangle; - angle_t diffang; - - if(CPlayer->health > 0) - { - if(weaponGrin) - { - weaponGrin = false; - if(CPlayer->bonuscount) - { - faceTimer = ST_GRINTIME; - faceIndex = ST_FACEGRIN; - return; - } - } - // getting hurt - if (CPlayer->damagecount) - { - int damageAngle = ST_FACEPAIN; - if(CPlayer->attacker && CPlayer->attacker != CPlayer->mo) - { - if(CPlayer->mo != NULL) - { - //some more doom_sbar C&P - badguyangle = R_PointToAngle2(CPlayer->mo->x, CPlayer->mo->y, CPlayer->attacker->x, CPlayer->attacker->y); - if (badguyangle > CPlayer->mo->angle) - { - // whether right or left - diffang = badguyangle - CPlayer->mo->angle; - i = diffang > ANG180; - } - else - { - // whether left or right - diffang = CPlayer->mo->angle - badguyangle; - i = diffang <= ANG180; - } // confusing, aint it? - if(i && diffang >= ANG45) - { - damageAngle = ST_FACEPAINRIGHT; - } - else if(!i && diffang >= ANG45) - { - damageAngle = ST_FACEPAINLEFT; - } - } - } - faceTimer = ST_PAINTIME; - if (mugshotHealth != -1 && CPlayer->health - mugshotHealth > 20) - { - faceIndex = ST_FACEOUCH; - } - else - { - faceIndex = damageAngle; - } - return; - } - if((CPlayer->cmd.ucmd.buttons & (BT_ATTACK|BT_ALTATTACK)) && !(CPlayer->cheats & (CF_FROZEN | CF_TOTALLYFROZEN))) - { - if(rampageTimer == ST_RAMPAGETIME) - { - faceIndex = ST_FACEPAIN; - faceTimer = 1; - } - else - { - rampageTimer++; - } - } - else - { - rampageTimer = 0; - } - // invulnerability - if (((CPlayer->cheats & CF_GODMODE) || (CPlayer->mo != NULL && CPlayer->mo->flags2 & MF2_INVULNERABLE)) && - (faceTimer == 0 || faceIndex <= 2)) - { - faceIndex = ST_FACEGOD + (number % 3); - faceTimer = ST_FACETIME; - } - - if (faceTimer == 0) - { - faceIndex = (number % 3); //should generate 0, 1, or 2 - faceTimer = ST_FACETIME; - } - faceTimer--; - mugshotHealth = CPlayer->health; - } - } - - void DrawInventoryBar(int type, int num, int x, int y, bool alwaysshow, - int counterx, int countery, EColorRange translation, bool drawArtiboxes, bool noArrows, bool alwaysshowcounter) - { //yes, there is some Copy & Paste here too - AInventory *item; - int i; - - // 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) - { - if(drawArtiboxes) - { - DrawImage (Images[invBarOffset + imgARTIBOX], x+i*31, y); - } - DrawDimImage (TexMan(item->Icon), x+i*31, y, item->Amount <= 0); - if(alwaysshowcounter || item->Amount != 1) - { - DrawNumber(item->Amount, 3, counterx+i*31, countery, translation); - } - if(item == CPlayer->mo->InvSel) - { - if(type == GAME_Heretic) - { - DrawImage(Images[invBarOffset + imgSELECTBOX], x+i*31, y+29); - } - else - { - DrawImage(Images[invBarOffset + imgSELECTBOX], x+i*31, y); - } - } - } - for (; i < num && drawArtiboxes; ++i) - { - DrawImage (Images[invBarOffset + imgARTIBOX], x+i*31, y); - } - // Is there something to the left? - if (!noArrows && CPlayer->mo->FirstInv() != CPlayer->mo->InvFirst) - { - DrawImage (Images[!(gametic & 4) ? - invBarOffset + imgINVLFGEM1 : invBarOffset + imgINVLFGEM2], x-12, y); - } - // Is there something to the right? - if (!noArrows && item != NULL) - { - DrawImage (Images[!(gametic & 4) ? - invBarOffset + imgINVRTGEM1 : invBarOffset + imgINVRTGEM2], x+num*31+2, y); - } - } - } - - //draws heretic/hexen style life gems - void DrawGem(FTexture* chain, FTexture* gem, int value, int x, int y, int padleft, int padright, int chainsize, - bool wiggle, bool translate) - { - if(value > 100) - value = 100; - else if(value < 0) - value = 0; - if(wiggle) - y += chainWiggle; - int gemWidth = gem->GetWidth(); - int chainWidth = chain->GetWidth(); - int offset = (int) (((double) (chainWidth-padleft-padright)/100)*value); - if(chain != NULL) - { - DrawImage(chain, x+(offset%chainsize), y); - } - if(gem != NULL) - DrawImage(gem, x+padleft+offset, y, translate ? getTranslation() : NULL); - } - - FRemapTable* getTranslation() - { - if(gameinfo.gametype & GAME_Raven) - return translationtables[TRANSLATION_PlayersExtra][int(CPlayer - players)]; - return translationtables[TRANSLATION_Players][int(CPlayer - players)]; - } - - FImageCollection Images; - FImageCollection Faces; - FPlayerSkin *oldSkin; - FFont *drawingFont; - FString lastPrefix; - bool weaponGrin; - int faceTimer; - int rampageTimer; - int faceIndex; - int oldHealth; - int oldArmor; - int mugshotHealth; - int chainWiggle; - int artiflash; - unsigned int invBarOffset; - FBarShader shader_horz_normal; - FBarShader shader_horz_reverse; - FBarShader shader_vert_normal; - FBarShader shader_vert_reverse; -}; - -IMPLEMENT_CLASS(DSBarInfo); - -DBaseStatusBar *CreateCustomStatusBar () -{ - return new DSBarInfo; -} diff --git a/src/g_shared/sbarinfo.h b/src/g_shared/sbarinfo.h index f93ed725f..86a43e13b 100644 --- a/src/g_shared/sbarinfo.h +++ b/src/g_shared/sbarinfo.h @@ -8,6 +8,7 @@ class FBarTexture; class FScanner; struct SBarInfoCommand; //we need to be able to use this before it is defined. +struct MugShotState; struct SBarInfoBlock { @@ -56,6 +57,7 @@ struct SBarInfo int GetGameType() { return gameType; } void ParseSBarInfo(int lump); void ParseSBarInfoBlock(FScanner &sc, SBarInfoBlock &block); + void ParseMugShotBlock(FScanner &sc, MugShotState &state); void getCoordinates(FScanner &sc, SBarInfoCommand &cmd); //retrieves the next two arguments as x and y. int getSignedInteger(FScanner &sc); //returns a signed integer. int newImage(const char* patchname); @@ -64,10 +66,255 @@ struct SBarInfo SBarInfo(); SBarInfo(int lumpnum); ~SBarInfo(); + static void Load(); }; extern SBarInfo *SBarInfoScript; void FreeSBarInfoScript(); +//Mug Shot scripting structs. All functions are defined in sbarinfo_parser.cpp +struct MugShotState; + +struct MugShotFrame +{ + TArray graphic; + int delay; + + MugShotFrame(); + ~MugShotFrame(); + FTexture *getTexture(FPlayerSkin *skn, int random, int level=0, int direction=0, bool usesLevels=false, bool health2=false, bool healthspecial=false, bool directional=false); +}; + + +struct MugShotState +{ + bool usesLevels; + bool health2; //health level is the 2nd character from the end. + bool healthspecial; //like health2 only the 2nd frame gets the normal health type. + bool directional; //faces direction of damage. + + unsigned int position; + int time; + int random; + bool finished; + FName state; + TArray frames; + + MugShotState(); + MugShotState(FString name); + ~MugShotState(); + void tick(); + void reset(); + MugShotFrame getCurrentFrame() { return frames[position]; } + FTexture *getCurrentFrameTexture(FPlayerSkin *skn, int level=0, int direction=0) { return getCurrentFrame().getTexture(skn, random, level, direction, usesLevels, health2, healthspecial, directional); } +}; + +extern TArray MugShotStates; + +const MugShotState *FindMugShotState(FString state); +int FindMugShotStateIndex(FName state); + +// Enums used between the parser and the display +enum //statusbar flags +{ + STATUSBARFLAG_FORCESCALED = 1, +}; + +enum //gametype flags +{ + GAMETYPE_SINGLEPLAYER = 1, + GAMETYPE_COOPERATIVE = 2, + GAMETYPE_DEATHMATCH = 4, + GAMETYPE_TEAMGAME = 8, +}; + +enum //drawimage flags +{ + DRAWIMAGE_PLAYERICON = 1, + DRAWIMAGE_AMMO1 = 2, + DRAWIMAGE_AMMO2 = 4, + DRAWIMAGE_INVENTORYICON = 8, + DRAWIMAGE_TRANSLATABLE = 16, + DRAWIMAGE_WEAPONSLOT = 32, + DRAWIMAGE_SWITCHABLE_AND = 64, + DRAWIMAGE_INVULNERABILITY = 128, + DRAWIMAGE_OFFSET_CENTER = 256, + DRAWIMAGE_ARMOR = 512, + DRAWIMAGE_WEAPONICON = 1024, +}; + +enum //drawnumber flags +{ + DRAWNUMBER_HEALTH = 1, + DRAWNUMBER_ARMOR = 2, + DRAWNUMBER_AMMO1 = 4, + DRAWNUMBER_AMMO2 = 8, + DRAWNUMBER_AMMO = 16, + DRAWNUMBER_AMMOCAPACITY = 32, + DRAWNUMBER_FRAGS = 64, + DRAWNUMBER_INVENTORY = 128, + DRAWNUMBER_KILLS = 256, + DRAWNUMBER_MONSTERS = 512, + DRAWNUMBER_ITEMS = 1024, + DRAWNUMBER_TOTALITEMS = 2048, + DRAWNUMBER_SECRETS = 4096, + DRAWNUMBER_TOTALSECRETS = 8192, + DRAWNUMBER_ARMORCLASS = 16384, +}; + +enum //drawbar flags (will go into special2) +{ + DRAWBAR_HORIZONTAL = 1, + DRAWBAR_REVERSE = 2, + DRAWBAR_COMPAREDEFAULTS = 4, + DRAWBAR_KEEPOFFSETS = 8, +}; + +enum //drawselectedinventory flags +{ + DRAWSELECTEDINVENTORY_ALTERNATEONEMPTY = 1, + DRAWSELECTEDINVENTORY_ARTIFLASH = 2, + DRAWSELECTEDINVENTORY_ALWAYSSHOWCOUNTER = 4, +}; + +enum //drawinventorybar flags +{ + DRAWINVENTORYBAR_ALWAYSSHOW = 1, + DRAWINVENTORYBAR_NOARTIBOX = 2, + DRAWINVENTORYBAR_NOARROWS = 4, + DRAWINVENTORYBAR_ALWAYSSHOWCOUNTER = 8, +}; + +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 = 1, + DRAWMUGSHOT_ANIMATEDGODMODE = 2, +}; + +enum //drawkeybar flags +{ + DRAWKEYBAR_VERTICAL = 1, +}; + +enum //event flags +{ + SBARINFOEVENT_NOT = 1, + SBARINFOEVENT_OR = 2, + SBARINFOEVENT_AND = 4, +}; + +enum //Key words +{ + SBARINFO_BASE, + SBARINFO_HEIGHT, + SBARINFO_INTERPOLATEHEALTH, + SBARINFO_INTERPOLATEARMOR, + SBARINFO_COMPLETEBORDER, + SBARINFO_STATUSBAR, + SBARINFO_MUGSHOT, +}; + +enum //Bar types +{ + STBAR_NONE, + STBAR_FULLSCREEN, + STBAR_NORMAL, + STBAR_AUTOMAP, + STBAR_INVENTORY, + STBAR_INVENTORYFULLSCREEN, +}; + +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_WEAPONAMMO, +}; + +//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(); + ~DSBarInfo(); + void Draw(EHudState state); + void NewGame(); + void AttachToPlayer(player_t *player); + void Tick(); + void ReceivedWeapon (AWeapon *weapon); + void FlashItem(const PClass *itemtype); + void SetMugShotState(const char* stateName, bool waitTillDone=false); +private: + void doCommands(SBarInfoBlock &block); + void DrawGraphic(FTexture* texture, int x, int y, int flags); + void DrawString(const char* str, int x, int y, EColorRange translation, int spacing=0); + void DrawNumber(int num, int len, int x, int y, EColorRange translation, int spacing=0); + void DrawFace(int accuracy, bool xdth, bool animatedgodmode, int x, int y); + int updateState(bool xdth, bool animatedgodmode); + void DrawInventoryBar(int type, int num, int x, int y, bool alwaysshow, + int counterx, int countery, EColorRange translation, bool drawArtiboxes, bool noArrows, bool alwaysshowcounter); + void DrawGem(FTexture* chain, FTexture* gem, int value, int x, int y, int padleft, int padright, int chainsize, + bool wiggle, bool translate); + FRemapTable* getTranslation(); + + FImageCollection Images; + FPlayerSkin *oldSkin; + FFont *drawingFont; + FString lastPrefix; + MugShotState *currentState; + bool weaponGrin; + bool damageFaceActive; + int lastDamageAngle; + int rampageTimer; + int oldHealth; + int oldArmor; + int mugshotHealth; + int chainWiggle; + int artiflash; + unsigned int invBarOffset; + FBarShader shader_horz_normal; + FBarShader shader_horz_reverse; + FBarShader shader_vert_normal; + FBarShader shader_vert_reverse; +}; + #endif //__SBarInfo_SBAR_H__ diff --git a/src/g_shared/sbarinfo_display.cpp b/src/g_shared/sbarinfo_display.cpp new file mode 100644 index 000000000..5e9ddbdb5 --- /dev/null +++ b/src/g_shared/sbarinfo_display.cpp @@ -0,0 +1,1335 @@ +#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" + +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) + +enum +{ + imgARTIBOX, + imgSELECTBOX, + imgINVLFGEM1, + imgINVLFGEM2, + imgINVRTGEM1, + imgINVRTGEM2, +}; + + +// Custom Mug Shot Stuff (Find mug shot state functions are with the parser). +MugShotFrame::MugShotFrame() +{ +} + +MugShotFrame::~MugShotFrame() +{ + graphic.Clear(); +} + +//Assemble a graphic name with the specified prefix and return the FTexture. +FTexture *MugShotFrame::getTexture(FPlayerSkin *skin, int random, int level, int direction, bool usesLevels, bool health2, bool healthspecial, bool directional) +{ + int index = !directional ? random % graphic.Size() : direction; + if(index > (signed int) (graphic.Size()-1)) + index = graphic.Size()-1; + char* sprite = new char[9]; + memcpy(sprite, skin->face[0] != 0 ? skin->face : "STF", 3); + memcpy(sprite+3, graphic[index], strlen(graphic[index])); + sprite[3+strlen(graphic[index])] = '\0'; + if(usesLevels) //change the last character to the level + { + if(!health2 && (!healthspecial || index == 1)) + sprite[2+strlen(graphic[index])] += level; + else + sprite[1+strlen(graphic[index])] += level; + } + return TexMan[TexMan.CheckForTexture(sprite, 0, true)]; +} + +MugShotState::MugShotState() +{ +} +MugShotState::MugShotState(FString name) +{ + name.ToLower(); + state = FName(name); + usesLevels = false; + health2 = false; + healthspecial = false; + directional = false; + random = M_Random(); +} + +MugShotState::~MugShotState() +{ + frames.Clear(); +} + +void MugShotState::tick() +{ + if(time == -1) //When the delay is negative 1 stay on this frame indefinitely + return; + if(time != 0) + { + time--; + } + else if(position != frames.Size()-1) + { + position++; + time = frames[position].delay; + random = M_Random(); + } + else + { + finished = true; + } +} + +void MugShotState::reset() +{ + time = frames[0].delay; + position = 0; + finished = false; + random = M_Random(); +} + +//Used for shading +FBarShader::FBarShader(bool vertical, bool reverse) //make an alpha map +{ + 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 : 1; + 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) * 256; +} + +const BYTE *FBarShader::GetPixels() +{ + return Pixels; +} + +void FBarShader::Unload() +{ +} + +//SBarInfo Display +DSBarInfo::DSBarInfo () : DBaseStatusBar (SBarInfoScript->height), + shader_horz_normal(false, false), + shader_horz_reverse(false, true), + shader_vert_normal(true, false), + shader_vert_reverse(true, true) +{ + static const char *InventoryBarLumps[] = + { + "ARTIBOX", "SELECTBO", "INVGEML1", + "INVGEML2", "INVGEMR1", "INVGEMR2", + "USEARTIA", "USEARTIB", "USEARTIC", "USEARTID", + }; + TArray patchnames; + patchnames.Resize(SBarInfoScript->Images.Size()+10); + unsigned int i = 0; + for(i = 0;i < SBarInfoScript->Images.Size();i++) + { + patchnames[i] = SBarInfoScript->Images[i]; + } + for(i = 0;i < 10;i++) + { + patchnames[i+SBarInfoScript->Images.Size()] = InventoryBarLumps[i]; + } + invBarOffset = SBarInfoScript->Images.Size(); + Images.Init(&patchnames[0], patchnames.Size()); + drawingFont = V_GetFont("ConFont"); + rampageTimer = 0; + oldHealth = 0; + oldArmor = 0; + mugshotHealth = -1; + lastPrefix = ""; + weaponGrin = false; + damageFaceActive = false; + lastDamageAngle = 1; + chainWiggle = 0; + artiflash = 4; + currentState = NULL; +} + +DSBarInfo::~DSBarInfo () +{ + Images.Uninit(); +} + +void DSBarInfo::Draw (EHudState state) +{ + DBaseStatusBar::Draw(state); + int hud = 2; + if(state == HUD_StatusBar) + { + if(SBarInfoScript->completeBorder) //Fill the statusbar with the border before we draw. + { + FTexture *b = TexMan[gameinfo.border->b]; + R_DrawBorder(viewwindowx, viewwindowy + realviewheight + b->GetHeight(), viewwindowx + realviewwidth, SCREENHEIGHT); + if(screenblocks == 10) + screen->FlatFill(viewwindowx, viewwindowy + realviewheight, viewwindowx + realviewwidth, viewwindowy + realviewheight + b->GetHeight(), b, true); + } + if(SBarInfoScript->automapbar && automapactive) + { + hud = 3; + } + else + { + hud = 2; + } + } + else if(state == HUD_Fullscreen) + { + hud = 1; + } + else + { + hud = 0; + } + if(SBarInfoScript->huds[hud].forceScaled) //scale the statusbar + { + SetScaled(true); + setsizeneeded = true; + } + doCommands(SBarInfoScript->huds[hud]); + if(CPlayer->inventorytics > 0 && !(level.flags & LEVEL_NOINVENTORYBAR)) + { + if(state == HUD_StatusBar) + doCommands(SBarInfoScript->huds[4]); + else if(state == HUD_Fullscreen) + doCommands(SBarInfoScript->huds[5]); + } +} + +void DSBarInfo::NewGame () +{ + if (CPlayer != NULL) + { + AttachToPlayer (CPlayer); + } +} + +void DSBarInfo::AttachToPlayer (player_t *player) +{ + player_t *oldplayer = CPlayer; + DBaseStatusBar::AttachToPlayer(player); +} + +void DSBarInfo::Tick () +{ + DBaseStatusBar::Tick(); + if(level.time & 1) + chainWiggle = pr_chainwiggle() & 1; + if(!SBarInfoScript->interpolateHealth) + { + oldHealth = CPlayer->health; + } + else + { + if(oldHealth > CPlayer->health) + { + oldHealth -= clamp((oldHealth - CPlayer->health) >> 2, 1, SBarInfoScript->interpolationSpeed); + } + else if(oldHealth < CPlayer->health) + { + oldHealth += clamp((CPlayer->health - oldHealth) >> 2, 1, SBarInfoScript->interpolationSpeed); + } + } + AInventory *armor = CPlayer->mo->FindInventory(); + if(armor == NULL) + { + oldArmor = 0; + } + else + { + if(!SBarInfoScript->interpolateArmor) + { + oldArmor = armor->Amount; + } + else + { + if(oldArmor > armor->Amount) + { + oldArmor -= clamp((oldArmor - armor->Amount) >> 2, 1, SBarInfoScript->armorInterpolationSpeed); + } + else if(oldArmor < armor->Amount) + { + oldArmor += clamp((armor->Amount - oldArmor) >> 2, 1, SBarInfoScript->armorInterpolationSpeed); + } + } + } + if(artiflash) + { + artiflash--; + } + + //Do some stuff related to the mug shot that has to be done at 35fps + if(currentState != NULL) + { + currentState->tick(); + if(currentState->finished) + currentState = NULL; + } + if((CPlayer->cmd.ucmd.buttons & (BT_ATTACK|BT_ALTATTACK)) && !(CPlayer->cheats & (CF_FROZEN | CF_TOTALLYFROZEN))) + { + if(rampageTimer != ST_RAMPAGETIME) + { + rampageTimer++; + } + } + else + { + rampageTimer = 0; + } + mugshotHealth = CPlayer->health; +} + +void DSBarInfo::ReceivedWeapon (AWeapon *weapon) +{ + weaponGrin = true; +} + +void DSBarInfo::FlashItem(const PClass *itemtype) +{ + artiflash = 4; +} + +//Public so it can be called by ACS +//Sets the mug shot state and resets it if it is not the state we are already on. +//waitTillDone is basically a priority variable when just to true the state won't change unless the previous state is finished. +void DSBarInfo::SetMugShotState(const char* stateName, bool waitTillDone) +{ + MugShotState *state = (MugShotState *) FindMugShotState(stateName); + if(state != currentState) + { + if(!waitTillDone || currentState == NULL || currentState->finished) + { + currentState = state; + state->reset(); + } + } +} + +void DSBarInfo::doCommands(SBarInfoBlock &block) +{ + //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(SBarInfoScript->interpolateHealth) + { + health = oldHealth; + } + if(SBarInfoScript->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 + { + 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 < MAX_WEAPONS_PER_SLOT; i++) + { + const PClass *weap = LocalWeapons.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 //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, cmd.flags); + else if(cmd.special2 != -1 && drawAlt == 2) + DrawGraphic(Images[cmd.special2], cmd.x, cmd.y, cmd.flags); + else if(cmd.special3 != -1 && drawAlt == 3) + DrawGraphic(Images[cmd.special3], cmd.x, cmd.y, cmd.flags); + break; + } + } + case SBARINFO_DRAWIMAGE: + if((cmd.flags & DRAWIMAGE_PLAYERICON)) + DrawGraphic(TexMan[CPlayer->mo->ScoreIcon], cmd.x, cmd.y, cmd.flags); + else if((cmd.flags & DRAWIMAGE_AMMO1)) + { + if(ammo1 != NULL) + DrawGraphic(TexMan[ammo1->Icon], cmd.x, cmd.y, cmd.flags); + } + else if((cmd.flags & DRAWIMAGE_AMMO2)) + { + if(ammo2 != NULL) + DrawGraphic(TexMan[ammo2->Icon], cmd.x, cmd.y, cmd.flags); + } + else if((cmd.flags & DRAWIMAGE_ARMOR)) + { + if(armor != NULL && armor->Amount != 0) + DrawGraphic(TexMan(armor->Icon), cmd.x, cmd.y, cmd.flags); + } + else if((cmd.flags & DRAWIMAGE_WEAPONICON)) + { + AWeapon *weapon = CPlayer->ReadyWeapon; + if(weapon != NULL && weapon->Icon > 0) + { + DrawGraphic(TexMan[weapon->Icon], cmd.x, cmd.y, cmd.flags); + } + } + else if((cmd.flags & DRAWIMAGE_INVENTORYICON)) + { + DrawGraphic(TexMan[cmd.sprite], cmd.x, cmd.y, cmd.flags); + } + else + { + DrawGraphic(Images[cmd.sprite], cmd.x, cmd.y, cmd.flags); + } + break; + case SBARINFO_DRAWNUMBER: + if(drawingFont != cmd.font) + { + drawingFont = cmd.font; + } + if(cmd.flags == DRAWNUMBER_HEALTH) + { + cmd.value = health; + if(cmd.value < 0) //health shouldn't display negatives + { + cmd.value = 0; + } + } + else if(cmd.flags == DRAWNUMBER_ARMOR) + { + cmd.value = armorAmount; + } + else if(cmd.flags == DRAWNUMBER_AMMO1) + { + cmd.value = ammocount1; + if(ammo1 == NULL) //no ammo, do not draw + { + continue; + } + } + else if(cmd.flags == DRAWNUMBER_AMMO2) + { + cmd.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) + { + cmd.value = item->Amount; + } + else + { + cmd.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) + { + cmd.value = item->MaxAmount; + } + else + { + cmd.value = ((AInventory *)GetDefaultByType(ammo))->MaxAmount; + } + } + else if(cmd.flags == DRAWNUMBER_FRAGS) + cmd.value = CPlayer->fragcount; + else if(cmd.flags == DRAWNUMBER_KILLS) + cmd.value = level.killed_monsters; + else if(cmd.flags == DRAWNUMBER_MONSTERS) + cmd.value = level.total_monsters; + else if(cmd.flags == DRAWNUMBER_ITEMS) + cmd.value = level.found_items; + else if(cmd.flags == DRAWNUMBER_TOTALITEMS) + cmd.value = level.total_items; + else if(cmd.flags == DRAWNUMBER_SECRETS) + cmd.value = level.found_secrets; + else if(cmd.flags == DRAWNUMBER_TOTALSECRETS) + cmd.value = level.total_secrets; + else if(cmd.flags == DRAWNUMBER_ARMORCLASS) + { + AHexenArmor *harmor = CPlayer->mo->FindInventory(); + if(harmor != NULL) + { + cmd.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) + { + cmd.value += armor->SavePercent; + } + cmd.value /= (5*FRACUNIT); + } + else if(cmd.flags == DRAWNUMBER_INVENTORY) + { + AInventory* item = CPlayer->mo->FindInventory(PClass::FindClass(cmd.string[0])); + if(item != NULL) + { + cmd.value = item->Amount; + } + else + { + cmd.value = 0; + } + } + if(cmd.special3 != -1 && cmd.value <= cmd.special3) //low + DrawNumber(cmd.value, cmd.special, cmd.x, cmd.y, cmd.translation2, cmd.special2); + else if(cmd.special4 != -1 && cmd.value >= cmd.special4) //high + DrawNumber(cmd.value, cmd.special, cmd.x, cmd.y, cmd.translation3, cmd.special2); + else + DrawNumber(cmd.value, cmd.special, cmd.x, cmd.y, cmd.translation, cmd.special2); + break; + case SBARINFO_DRAWMUGSHOT: + { + bool xdth = false; + bool animatedgodmode = false; + if(cmd.flags & DRAWMUGSHOT_XDEATHFACE) + xdth = true; + if(cmd.flags & DRAWMUGSHOT_ANIMATEDGODMODE) + animatedgodmode = true; + DrawFace(cmd.special, xdth, animatedgodmode, cmd.x, cmd.y); + break; + } + case SBARINFO_DRAWSELECTEDINVENTORY: + if(CPlayer->mo->InvSel != NULL && !(level.flags & LEVEL_NOINVENTORYBAR)) + { + if((cmd.flags & DRAWSELECTEDINVENTORY_ARTIFLASH) && artiflash) + { + DrawDimImage(Images[ARTIFLASH_OFFSET+(4-artiflash)], cmd.x, cmd.y, CPlayer->mo->InvSel->Amount <= 0); + } + else + { + DrawDimImage(TexMan(CPlayer->mo->InvSel->Icon), cmd.x, cmd.y, CPlayer->mo->InvSel->Amount <= 0); + } + if((cmd.flags & DRAWSELECTEDINVENTORY_ALWAYSSHOWCOUNTER) || CPlayer->mo->InvSel->Amount != 1) + { + if(drawingFont != cmd.font) + { + drawingFont = cmd.font; + } + DrawNumber(CPlayer->mo->InvSel->Amount, 3, cmd.special2, cmd.special3, cmd.translation, cmd.special4); + } + } + else if((cmd.flags & DRAWSELECTEDINVENTORY_ALTERNATEONEMPTY)) + { + doCommands(cmd.subBlock); + } + break; + case SBARINFO_DRAWINVENTORYBAR: + { + bool alwaysshow = false; + bool artibox = true; + bool noarrows = false; + bool alwaysshowcounter = false; + 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(drawingFont != cmd.font) + { + drawingFont = cmd.font; + } + DrawInventoryBar(cmd.special, cmd.value, cmd.x, cmd.y, alwaysshow, cmd.special2, cmd.special3, cmd.translation, artibox, noarrows, alwaysshowcounter); + break; + } + case SBARINFO_DRAWBAR: + { + if(cmd.sprite == -1 || Images[cmd.sprite] == 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->GetDefault()->health; + } + } + 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; + } + } + 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.sprite] != NULL); + + FTexture *fg = Images[cmd.sprite]; + FTexture *bg = (cmd.special != -1) ? Images[cmd.special] : NULL; + int x, y, w, h; + int cx, cy, cw, ch, cr, cb; + + // Calc real screen coordinates for bar + x = cmd.x + ST_X; + y = cmd.y + ST_Y; + w = fg->GetScaledWidth(); + h = fg->GetScaledHeight(); + if (Scaled) + { + screen->VirtualToRealCoordsInt(x, y, w, h, 320, 200, true); + } + if(cmd.special2 & DRAWBAR_KEEPOFFSETS) + { + x += fg->LeftOffset; + y += fg->TopOffset; + } + + if(cmd.special3 != 0) + { + //Draw the whole foreground + screen->DrawTexture(fg, x, y, + DTA_DestWidth, w, + DTA_DestHeight, h, + TAG_DONE); + } + else + { + // Draw background + if (bg != NULL && bg->GetScaledWidth() == fg->GetScaledWidth() && bg->GetScaledHeight() == fg->GetScaledHeight()) + { + screen->DrawTexture(bg, x, y, + DTA_DestWidth, w, + DTA_DestHeight, h, + TAG_DONE); + } + else + { + screen->Clear(x, y, x + w, y + h, GPalette.BlackIndex, 0); + } + } + + // Calc clipping rect for background + cx = cmd.x + ST_X + cmd.special3; + cy = cmd.y + ST_Y + cmd.special3; + cw = fg->GetScaledWidth() - cmd.special3 * 2; + ch = fg->GetScaledHeight() - cmd.special3 * 2; + if (Scaled) + { + screen->VirtualToRealCoordsInt(cx, cy, cw, ch, 320, 200, true); + } + if(cmd.special2 & DRAWBAR_KEEPOFFSETS) + { + cx += fg->LeftOffset; + cy += fg->TopOffset; + } + 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; + } + + // Draw background + if(cmd.special3 != 0) + { + if (bg != NULL && bg->GetScaledWidth() == fg->GetScaledWidth() && bg->GetScaledHeight() == fg->GetScaledHeight()) + { + screen->DrawTexture(bg, x, y, + DTA_DestWidth, w, + DTA_DestHeight, h, + DTA_ClipLeft, cx, + DTA_ClipTop, cy, + DTA_ClipRight, cr, + DTA_ClipBottom, cb, + TAG_DONE); + } + else + { + screen->Clear(cx, cy, cr, cb, GPalette.BlackIndex, 0); + } + } + else + { + screen->DrawTexture(fg, x, y, + DTA_DestWidth, w, + DTA_DestHeight, h, + DTA_ClipLeft, cx, + DTA_ClipTop, cy, + DTA_ClipRight, cr, + DTA_ClipBottom, cb, + TAG_DONE); + } + break; + } + case SBARINFO_DRAWGEM: + { + int value = (cmd.flags & DRAWGEM_ARMOR) ? armorAmount : health; + int max = 100; + 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.sprite], value, cmd.x, cmd.y, 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); + screen->DrawTexture (shaders[(vertical << 1) + reverse], ST_X+cmd.x, ST_Y+cmd.y, + DTA_DestWidth, cmd.special, + DTA_DestHeight, cmd.special2, + DTA_Bottom320x200, Scaled, + DTA_AlphaChannel, true, + DTA_FillColor, 0, + 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, cmd.translation); + break; + case SBARINFO_DRAWKEYBAR: + { + bool vertical = !!(cmd.flags & DRAWKEYBAR_VERTICAL); + AInventory *item = CPlayer->mo->Inventory; + if(item == NULL) + break; + for(int i = 0;i < cmd.value;i++) + { + while(item->Icon <= 0 || item->GetClass() == RUNTIME_CLASS(AKey) || !item->IsKindOf(RUNTIME_CLASS(AKey))) + { + item = item->Inventory; + if(item == NULL) + goto FinishDrawKeyBar; + } + if(!vertical) + DrawImage(TexMan[item->Icon], cmd.x+(cmd.special*i), cmd.y); + else + DrawImage(TexMan[item->Icon], cmd.x, cmd.y+(cmd.special*i)); + 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); + } + break; + case SBARINFO_PLAYERCLASS: + { + int spawnClass = CPlayer->cls->ClassIndex; + if(cmd.special == spawnClass || cmd.special2 == spawnClass || cmd.special3 == spawnClass) + { + doCommands(cmd.subBlock); + } + 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); + 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); + } + else if(cmd.flags & SBARINFOEVENT_NOT) + { + doCommands(cmd.subBlock); + } + } + 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); + } + else if(cmd.flags & SBARINFOEVENT_NOT) + { + doCommands(cmd.subBlock); + } + } + } + break; + } + } +} + +//draws an image with the specified flags +void DSBarInfo::DrawGraphic(FTexture* texture, int x, int y, int flags) +{ + if((flags & DRAWIMAGE_OFFSET_CENTER)) + { + x -= (texture->GetWidth()/2)-texture->LeftOffset; + y -= (texture->GetHeight()/2)-texture->TopOffset; + } + if((flags & DRAWIMAGE_TRANSLATABLE)) + DrawImage(texture, x, y, getTranslation()); + else + DrawImage(texture, x, y); +} + +void DSBarInfo::DrawString(const char* str, int x, int y, EColorRange translation, int spacing) +{ + x += spacing; + while(*str != '\0') + { + if(*str == ' ') + { + x += drawingFont->GetSpaceWidth(); + str++; + continue; + } + int width = drawingFont->GetCharWidth((int) *str); + FTexture* character = drawingFont->GetChar((int) *str, &width); + if(character == NULL) //missing character. + { + str++; + continue; + } + x += (character->LeftOffset+1); //ignore x offsets since we adapt to character size + DrawImage(character, x, y, drawingFont->GetColorTranslation(translation)); + x += width + spacing - (character->LeftOffset+1); + str++; + } +} + +//draws the specified number up to len digits +void DSBarInfo::DrawNumber(int num, int len, int x, int y, EColorRange translation, int spacing) +{ + FString value; + int maxval = (int) ceil(pow(10., len))-1; + num = clamp(num, -maxval, maxval); + value.Format("%d", num); + x -= int(drawingFont->StringWidth(value)+(spacing * value.Len())); + DrawString(value, x, y, translation, spacing); +} + +//draws the mug shot +void DSBarInfo::DrawFace(int accuracy, bool xdth, bool animatedgodmode, int x, int y) +{ + int angle = updateState(xdth, animatedgodmode); + int level = 0; + for(level = 0;CPlayer->health < (accuracy-level-1)*(CPlayer->mo->GetMaxHealth()/accuracy);level++); + if(currentState != NULL) + { + DrawImage(currentState->getCurrentFrameTexture(&skins[CPlayer->userinfo.skin], level, angle), x, y); + } +} + +int DSBarInfo::updateState(bool xdth, bool animatedgodmode) +{ + int i; + angle_t badguyangle; + angle_t diffang; + + if(CPlayer->health > 0) + { + if(weaponGrin) + { + weaponGrin = false; + if(CPlayer->bonuscount) + { + SetMugShotState("grin", false); + return 0; + } + } + + if (CPlayer->damagecount) + { + int damageAngle = 1; + if(CPlayer->attacker && CPlayer->attacker != CPlayer->mo) + { + if(CPlayer->mo != NULL) + { + //The next 12 lines is from the Doom statusbar code. + badguyangle = R_PointToAngle2(CPlayer->mo->x, CPlayer->mo->y, CPlayer->attacker->x, CPlayer->attacker->y); + if(badguyangle > CPlayer->mo->angle) + { + // whether right or left + diffang = badguyangle - CPlayer->mo->angle; + i = diffang > ANG180; + } + else + { + // whether left or right + diffang = CPlayer->mo->angle - badguyangle; + i = diffang <= ANG180; + } // confusing, aint it? + if(i && diffang >= ANG45) + { + damageAngle = 0; + } + else if(!i && diffang >= ANG45) + { + damageAngle = 2; + } + } + } + const char* stateName = new char[5]; + if (mugshotHealth != -1 && CPlayer->health - mugshotHealth > 20) + stateName = "ouch"; + else + stateName = "pain"; + char* fullStateName = new char[sizeof(stateName)+sizeof((const char*) CPlayer->LastDamageType) + 1]; + sprintf(fullStateName, "%s.%s", stateName, (const char*) CPlayer->LastDamageType); + if(FindMugShotState(fullStateName) != NULL) + SetMugShotState(fullStateName); + else + SetMugShotState(stateName); + damageFaceActive = !(currentState == NULL); + lastDamageAngle = damageAngle; + return damageAngle; + } + if(damageFaceActive) + { + if(currentState == NULL) + damageFaceActive = false; + else + { + const char* stateName = new char[5]; + if (mugshotHealth != -1 && CPlayer->health - mugshotHealth > 20) + stateName = "ouch"; + else + stateName = "pain"; + char* fullStateName = new char[sizeof(stateName)+sizeof((const char*) CPlayer->LastDamageType) + 1]; + sprintf(fullStateName, "%s.%s", stateName, (const char*) CPlayer->LastDamageType); + if(FindMugShotState(fullStateName) != NULL) + SetMugShotState(fullStateName); + else + SetMugShotState(stateName); + return lastDamageAngle; + } + } + + if(rampageTimer == ST_RAMPAGETIME) + { + SetMugShotState("rampage", true); + return 0; + } + + if((CPlayer->cheats & CF_GODMODE) || (CPlayer->mo != NULL && CPlayer->mo->flags2 & MF2_INVULNERABLE)) + { + if(animatedgodmode) + SetMugShotState("godanimated", true); + else + SetMugShotState("god", true); + } + else + SetMugShotState("normal", true); + } + else + { + const char* stateName = new char[7]; + if(!xdth || !(CPlayer->cheats & CF_EXTREMELYDEAD)) + stateName = "death"; + else + stateName = "xdeath"; + //new string the size of stateName and the damage type put together + char* fullStateName = new char[sizeof(stateName)+sizeof((const char*) CPlayer->LastDamageType) + 1]; + sprintf(fullStateName, "%s.%s", stateName, (const char*) CPlayer->LastDamageType); + if(FindMugShotState(fullStateName) != NULL) + SetMugShotState(fullStateName); + else + SetMugShotState(stateName); + } + return 0; +} + +void DSBarInfo::DrawInventoryBar(int type, int num, int x, int y, bool alwaysshow, + int counterx, int countery, EColorRange translation, bool drawArtiboxes, bool noArrows, bool alwaysshowcounter) +{ //yes, there is some Copy & Paste here too + AInventory *item; + int i; + + // 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) + { + if(drawArtiboxes) + { + DrawImage (Images[invBarOffset + imgARTIBOX], x+i*31, y); + } + DrawDimImage (TexMan(item->Icon), x+i*31, y, item->Amount <= 0); + if(alwaysshowcounter || item->Amount != 1) + { + DrawNumber(item->Amount, 3, counterx+i*31, countery, translation); + } + if(item == CPlayer->mo->InvSel) + { + if(type == GAME_Heretic) + { + DrawImage(Images[invBarOffset + imgSELECTBOX], x+i*31, y+29); + } + else + { + DrawImage(Images[invBarOffset + imgSELECTBOX], x+i*31, y); + } + } + } + for (; i < num && drawArtiboxes; ++i) + { + DrawImage (Images[invBarOffset + imgARTIBOX], x+i*31, y); + } + // Is there something to the left? + if (!noArrows && CPlayer->mo->FirstInv() != CPlayer->mo->InvFirst) + { + DrawImage (Images[!(gametic & 4) ? + invBarOffset + imgINVLFGEM1 : invBarOffset + imgINVLFGEM2], x-12, y); + } + // Is there something to the right? + if (!noArrows && item != NULL) + { + DrawImage (Images[!(gametic & 4) ? + invBarOffset + imgINVRTGEM1 : invBarOffset + imgINVRTGEM2], x+num*31+2, y); + } + } +} + +//draws heretic/hexen style life gems +void DSBarInfo::DrawGem(FTexture* chain, FTexture* gem, int value, int x, int y, int padleft, int padright, int chainsize, + bool wiggle, bool translate) +{ + if(value > 100) + value = 100; + else if(value < 0) + value = 0; + if(wiggle) + y += chainWiggle; + int gemWidth = gem->GetWidth(); + int chainWidth = chain->GetWidth(); + int offset = (int) (((double) (chainWidth-padleft-padright)/100)*value); + if(chain != NULL) + { + DrawImage(chain, x+(offset%chainsize), y); + } + if(gem != NULL) + DrawImage(gem, x+padleft+offset, y, translate ? getTranslation() : NULL); +} + +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 () +{ + return new DSBarInfo; +} diff --git a/src/g_shared/sbarinfo_parser.cpp b/src/g_shared/sbarinfo_parser.cpp new file mode 100644 index 000000000..d1b80cd98 --- /dev/null +++ b/src/g_shared/sbarinfo_parser.cpp @@ -0,0 +1,1076 @@ +#include "doomtype.h" +#include "doomstat.h" +#include "sc_man.h" +#include "v_font.h" +#include "w_wad.h" +#include "sbar.h" +#include "d_player.h" +#include "sbarinfo.h" +#include "templates.h" +#include "m_random.h" +#include "gi.h" +#include "i_system.h" + +SBarInfo *SBarInfoScript; +TArray MugShotStates; + +static const char *SBarInfoTopLevel[] = +{ + "base", + "height", + "interpolatehealth", + "interpolatearmor", + "completeborder", + "statusbar", + "mugshot", + NULL +}; + +static const char *StatusBars[] = +{ + "none", + "fullscreen", + "normal", + "automap", + "inventory", + "inventoryfullscreen", + NULL +}; + +static const char *SBarInfoRoutineLevel[] = +{ + "drawimage", + "drawnumber", + "drawswitchableimage", + "drawmugshot", + "drawselectedinventory", + "drawinventorybar", + "drawbar", + "drawgem", + "drawshader", + "drawstring", + "drawkeybar", + "gamemode", + "playerclass", + "weaponammo", //event + NULL +}; + +static void FreeSBarInfoScript() +{ + if (SBarInfoScript != NULL) + { + delete SBarInfoScript; + SBarInfoScript = NULL; + } +} + +void SBarInfo::Load() +{ + 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 == NULL) + SBarInfoScript = new SBarInfo(lump); + else //We now have to load multiple SBarInfo Lumps so the 2nd time we need to use this method instead. + SBarInfoScript->ParseSBarInfo(lump); + } + atterm(FreeSBarInfoScript); + } +} + +//SBarInfo Script Reader +void SBarInfo::ParseSBarInfo(int lump) +{ + gameType = gameinfo.gametype; + Printf("%d=%d", gameinfo.gametype, GAME_Any); + bool baseSet = false; + FScanner sc(lump, Wads.GetLumpFullName(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); //zip/pk3 + //Do a normal wad lookup. + if (lump == -1 && sc.StringLen <= 8 && !strchr(sc.String, '/')) + lump = Wads.CheckNumForName(sc.String); + 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")) + gameType = GAME_Doom; + 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_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(); + while(sc.CheckToken(',')) + { + sc.MustGetToken(TK_Identifier); + if(sc.Compare("forcescaled")) + { + this->huds[barNum].forceScaled = true; + } + else + { + sc.ScriptError("Unkown flag '%s'.", sc.String); + } + } + sc.MustGetToken('{'); + if(barNum == STBAR_AUTOMAP) + { + automapbar = true; + } + ParseSBarInfoBlock(sc, this->huds[barNum]); + break; + } + case SBARINFO_MUGSHOT: + { + sc.MustGetToken(TK_StringConst); + MugShotState state(sc.String); + if(sc.CheckToken(',')) //first loop must be a comma + { + do + { + sc.MustGetToken(TK_Identifier); + if(sc.Compare("health")) + state.usesLevels = true; + else if(sc.Compare("health2")) + state.usesLevels = state.health2 = true; + else if(sc.Compare("healthspecial")) + state.usesLevels = state.healthspecial = true; + else if(sc.Compare("directional")) + state.directional = true; + else + sc.ScriptError("Unknown MugShot state flag '%s'.", sc.String); + } + while(sc.CheckToken(',') || sc.CheckToken('|')); + } + ParseMugShotBlock(sc, state); + int index = 0; + if((index = FindMugShotStateIndex(state.state)) != -1) //We already had this state, remove the old one. + { + MugShotStates.Delete(index); + } + MugShotStates.Push(state); + 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 + { + 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; + 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("translatable")) + { + cmd.flags += DRAWIMAGE_TRANSLATABLE; + getImage = true; + } + else + { + 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 = ((AInventory *)GetDefaultByType(item))->Icon; + } + } + if(getImage) + { + sc.MustGetToken(TK_StringConst); + cmd.sprite = newImage(sc.String); + } + sc.MustGetToken(','); + this->getCoordinates(sc, cmd); + if(sc.CheckToken(',')) + { + sc.MustGetToken(TK_Identifier); + if(sc.Compare("center")) + cmd.flags += DRAWIMAGE_OFFSET_CENTER; + else + sc.ScriptError("Expected 'center' got '%s' instead.", 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 + { + cmd.flags = DRAWNUMBER_INVENTORY; + sc.MustGetToken(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 ammo + { + sc.ScriptError("'%s' is not a type of inventory item.", sc.String); + } + } + sc.MustGetToken(','); + } + this->getCoordinates(sc, cmd); + 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: + sc.MustGetToken(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 + sc.ScriptError("Unknown flag '%s'.", sc.String); + if(!sc.CheckToken('|')) + sc.MustGetToken(','); + } + this->getCoordinates(sc, cmd); + 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 + { + 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(','); + } + sc.MustGetToken(TK_IntConst); + cmd.x = sc.Number; + sc.MustGetToken(','); + sc.MustGetToken(TK_IntConst); + cmd.y = sc.Number - (200 - this->height); + cmd.special2 = cmd.x + 30; + cmd.special3 = cmd.y + 24; + cmd.translation = CR_GOLD; + if(sc.CheckToken(',')) //more font information + { + sc.MustGetToken(TK_IntConst); + cmd.special2 = sc.Number; + sc.MustGetToken(','); + sc.MustGetToken(TK_IntConst); + cmd.special3 = sc.Number - (200 - this->height); + 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('{'); + this->ParseSBarInfoBlock(sc, cmd.subBlock); + } + else + { + sc.MustGetToken(';'); + } + break; + } + case SBARINFO_DRAWINVENTORYBAR: + sc.MustGetToken(TK_Identifier); + if(sc.Compare("Heretic")) + { + cmd.special = GAME_Heretic; + } + if(sc.Compare("Doom") || sc.Compare("Heretic")) + { + 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 + { + 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); + } + else + { + sc.ScriptError("Unkown style '%s'.", sc.String); + } + sc.MustGetToken(','); + this->getCoordinates(sc, cmd); + cmd.special2 = cmd.x + 26; + cmd.special3 = cmd.y + 22; + cmd.translation = CR_GOLD; + if(sc.CheckToken(',')) //more font information + { + sc.MustGetToken(TK_IntConst); + cmd.special2 = sc.Number; + sc.MustGetToken(','); + sc.MustGetToken(TK_IntConst); + cmd.special3 = sc.Number - (200 - this->height); + 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.sprite = newImage(sc.String); + 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 + { + 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)) //must be a kind of ammo + { + 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 if(sc.Compare("keepoffsets")) + cmd.special2 += DRAWBAR_KEEPOFFSETS; + else + sc.ScriptError("Unkown flag '%s'.", sc.String); + if(!sc.CheckToken('|')) + sc.MustGetToken(','); + } + this->getCoordinates(sc, cmd); + 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.sprite = newImage(sc.String); + 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, cmd); + 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, cmd); + 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, cmd); + 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(','); + sc.MustGetToken(TK_IntConst); + cmd.special = sc.Number; + sc.MustGetToken(','); + this->getCoordinates(sc, cmd); + 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 + sc.ScriptError("Unknown gamemode: %s", sc.String); + if(sc.CheckToken('{')) + break; + sc.MustGetToken(','); + } + 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: + 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('{'); + this->ParseSBarInfoBlock(sc, cmd.subBlock); + break; + } + block.commands.Push(cmd); + } + sc.MustGetToken('}'); +} + +void SBarInfo::ParseMugShotBlock(FScanner &sc, MugShotState &state) +{ + sc.MustGetToken('{'); + while(!sc.CheckToken('}')) + { + MugShotFrame frame; + bool multiframe = false; + if(sc.CheckToken('{')) + multiframe = true; + do + { + sc.MustGetToken(TK_Identifier); + if(strlen(sc.String) > 5) + sc.ScriptError("MugShot frames can not 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, SBarInfoCommand &cmd) +{ + bool negative = false; + negative = sc.CheckToken('-'); + sc.MustGetToken(TK_IntConst); + cmd.x = negative ? -sc.Number : sc.Number; + sc.MustGetToken(','); + negative = sc.CheckToken('-'); + sc.MustGetToken(TK_IntConst); + cmd.y = (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(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, 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; + interpolationSpeed = 8; + armorInterpolationSpeed = 8; + height = 0; +} + +SBarInfo::~SBarInfo() +{ + for (size_t i = 0; i < countof(huds); ++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 = 0; + y = 0; + value = 0; + sprite = 0; + translation = CR_UNTRANSLATED; + translation2 = CR_UNTRANSLATED; + translation3 = CR_UNTRANSLATED; + font = V_GetFont("CONFONT"); +} + +SBarInfoCommand::~SBarInfoCommand() +{ +} + +SBarInfoBlock::SBarInfoBlock() +{ + forceScaled = false; +} + +const MugShotState *FindMugShotState(FString state) +{ + state.ToLower(); + for(unsigned int i = 0;i < MugShotStates.Size();i++) + { + if(MugShotStates[i].state == state) + return &MugShotStates[i]; + } + return NULL; +} + +//Used to allow replacements of states +int FindMugShotStateIndex(FName state) +{ + for(unsigned int i = 0;i < MugShotStates.Size();i++) + { + if(MugShotStates[i].state == state) + return i; + } + return -1; +} diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 0fb109397..0aff6279d 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -67,6 +67,7 @@ #include "c_bind.h" #include "info.h" #include "r_translate.h" +#include "sbarinfo.h" extern FILE *Logfile; @@ -5301,6 +5302,7 @@ int DLevelScript::RunScript () } case PCD_GETACTORLIGHTLEVEL: + { AActor *actor = SingleActorFromTID(STACK(1), activator); if (actor != NULL) { @@ -5309,6 +5311,15 @@ int DLevelScript::RunScript () else STACK(1)=0; break; } + + case PCD_SETMUGSHOTSTATE: + if(StatusBar != NULL && StatusBar->IsKindOf(RUNTIME_CLASS(DSBarInfo))) + { + static_cast(StatusBar)->SetMugShotState(FBehavior::StaticLookupString(STACK(1))); + } + break; + + } } if (state == SCRIPT_DivideBy0) diff --git a/src/p_acs.h b/src/p_acs.h index a6168abc4..b94843a2b 100644 --- a/src/p_acs.h +++ b/src/p_acs.h @@ -547,6 +547,7 @@ public: PCD_CHECKACTORCEILINGTEXTURE, PCD_CHECKACTORFLOORTEXTURE, /*340*/ PCD_GETACTORLIGHTLEVEL, + PCD_SETMUGSHOTSTATE, PCODE_COMMAND_COUNT }; diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index f07b89d20..da2a5f02d 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -1,3 +1,37 @@ +/* +** p_converstation.cpp +** Implements Strife style conversation dialogs +** +**--------------------------------------------------------------------------- +** Copyright 2004-2008 Randy Heit +** 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 #include "actor.h" diff --git a/src/r_defs.h b/src/r_defs.h index dd1174573..99a1f464a 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -272,6 +272,7 @@ struct sector_t; struct extsector_t { + // 3DMIDTEX information struct midtex { struct plane @@ -280,6 +281,14 @@ struct extsector_t TArray AttachedLines; // all 3dMidtex lines attached to this sector } Floor, Ceiling; } Midtex; + + // linked sectors + /* + struct linked + { + TArray Sectors; + } Linked; + */ void Serialize(FArchive &arc); }; diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/thingdef/thingdef_codeptr.cpp index e4c49b32e..9aa406e14 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/thingdef/thingdef_codeptr.cpp @@ -550,7 +550,11 @@ void A_JumpIfCloser(AActor * self) if (target==NULL) return; fixed_t dist = fixed_t(EvalExpressionF (StateParameters[index], self) * FRACUNIT); - if (index > 0 && P_AproxDistance(self->x-target->x, self->y-target->y) < dist) + if (index > 0 && P_AproxDistance(self->x-target->x, self->y-target->y) < dist && + ( (self->z > target->z && self->z - (target->z + target->height) < dist) || + (self->z <=target->z && target->z - (self->z + self->height) < dist) + ) + ) DoJump(self, CallingState, StateParameters[index+1]); } diff --git a/tools/updaterevision/updaterevision.vcproj b/tools/updaterevision/updaterevision.vcproj index 202c9d042..f39914dca 100644 --- a/tools/updaterevision/updaterevision.vcproj +++ b/tools/updaterevision/updaterevision.vcproj @@ -1,7 +1,7 @@ - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + +