From 7e900c101680dcad6eff53d12eb0521042b1069d Mon Sep 17 00:00:00 2001
From: Christoph Oelckers <coelckers@zdoom.fake>
Date: Mon, 24 Mar 2008 17:48:55 +0000
Subject: [PATCH] - Reverted changes of r715 in v_collection.cpp because they
 broke loading   of status bar face graphics belonging to skins. SBARINFO
 update #15 - Fixed: Monospacing fonts wasn't quite correct. - Fixed: The new
 mug shot code forgot to use the first arg of drawmugshot (the   one that
 picks the default sprite prefix). - Added: lowerHealthCap variable to
 SBarInfo, which is set to true by default. - Added: ininventory event to
 SBarInfo to detect if one or two items are in (or   not in) the player's
 inventory. - Added: The ability to print global vars using drawnumber.  I
 need someone to   test it though. - Added: aspectratio command to detect what
 the user's aspect ratio is. - Added: missing spacing argument to drawstring.
 - Changed the sbarinfo display routine for drawnumber to not use cmd.value to
   store what it is about to display.  Now it uses a new variable. - More
 conversions from DrawImage to screen->DrawTexture.  I think only the  
 inventory bar drawing functions have to be changed now.

SVN r846 (trunk)
---
 docs/rh-log.txt                   |  19 ++++
 src/g_shared/sbarinfo.h           |  21 +++-
 src/g_shared/sbarinfo_display.cpp | 158 ++++++++++++++++++++++--------
 src/g_shared/sbarinfo_parser.cpp  |  79 ++++++++++++++-
 src/v_collection.cpp              |   8 +-
 src/win32/i_input.cpp             |   3 +
 6 files changed, 243 insertions(+), 45 deletions(-)

diff --git a/docs/rh-log.txt b/docs/rh-log.txt
index 5277a741f..00bacfc5a 100644
--- a/docs/rh-log.txt
+++ b/docs/rh-log.txt
@@ -1,3 +1,22 @@
+March 24, 2008 (Changes by Graf Zahl)
+- Reverted changes of r715 in v_collection.cpp because they broke loading
+  of status bar face graphics belonging to skins.
+SBARINFO update #15
+- Fixed: Monospacing fonts wasn't quite correct.
+- Fixed: The new mug shot code forgot to use the first arg of drawmugshot (the
+  one that picks the default sprite prefix).
+- Added: lowerHealthCap variable to SBarInfo, which is set to true by default.
+- Added: ininventory event to SBarInfo to detect if one or two items are in (or
+  not in) the player's inventory.
+- Added: The ability to print global vars using drawnumber.  I need someone to
+  test it though.
+- Added: aspectratio command to detect what the user's aspect ratio is.
+- Added: missing spacing argument to drawstring.
+- Changed the sbarinfo display routine for drawnumber to not use cmd.value to
+  store what it is about to display.  Now it uses a new variable.
+- More conversions from DrawImage to screen->DrawTexture.  I think only the
+  inventory bar drawing functions have to be changed now.
+
 March 23, 2008 (Changes by Graf Zahl)
 - Fixed: The Sequence pointer in ASoundSequenceSlot was not declared as
   a pointer and it was missing both read and write barriers.
diff --git a/src/g_shared/sbarinfo.h b/src/g_shared/sbarinfo.h
index 548961a92..217f89dd5 100644
--- a/src/g_shared/sbarinfo.h
+++ b/src/g_shared/sbarinfo.h
@@ -86,6 +86,7 @@ struct SBarInfo
 	bool interpolateHealth;
 	bool interpolateArmor;
 	bool completeBorder;
+	bool lowerHealthCap;
 	char spacingCharacter;
 	int interpolationSpeed;
 	int armorInterpolationSpeed;
@@ -119,7 +120,7 @@ struct MugShotFrame
 
 	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);
+	FTexture *getTexture(FString &defaultFace, FPlayerSkin *skn, int random, int level=0, int direction=0, bool usesLevels=false, bool health2=false, bool healthspecial=false, bool directional=false);
 };
 
 
@@ -143,7 +144,7 @@ struct 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); }
+	FTexture *getCurrentFrameTexture(FString &defaultFace, FPlayerSkin *skn, int level=0, int direction=0) { return getCurrentFrame().getTexture(defaultFace, skn, random, level, direction, usesLevels, health2, healthspecial, directional); }
 };
 
 extern TArray<MugShotState> MugShotStates;
@@ -197,6 +198,7 @@ enum //drawnumber flags
 	DRAWNUMBER_SECRETS = 4096,
 	DRAWNUMBER_TOTALSECRETS = 8192,
 	DRAWNUMBER_ARMORCLASS = 16384,
+	DRAWNUMBER_GLOBALVAR = 32768,
 };
 
 enum //drawbar flags (will go into special2)
@@ -253,6 +255,14 @@ enum //event flags
 	SBARINFOEVENT_AND = 4,
 };
 
+enum //aspect ratios
+{
+	ASPECTRATIO_4_3 = 0,
+	ASPECTRATIO_16_9 = 1,
+	ASPECTRATIO_16_10 = 2,
+	ASPECTRATIO_5_4 = 3,
+};
+
 enum //Key words
 {
 	SBARINFO_BASE,
@@ -261,6 +271,7 @@ enum //Key words
 	SBARINFO_INTERPOLATEARMOR,
 	SBARINFO_COMPLETEBORDER,
 	SBARINFO_MONOSPACEFONTS,
+	SBARINFO_LOWERHEALTHCAP,
 	SBARINFO_STATUSBAR,
 	SBARINFO_MUGSHOT,
 };
@@ -293,7 +304,9 @@ enum //Bar key words
 	SBARINFO_DRAWKEYBAR,
 	SBARINFO_GAMEMODE,
 	SBARINFO_PLAYERCLASS,
+	SBARINFO_ASPECTRATIO,
 	SBARINFO_WEAPONAMMO,
+	SBARINFO_ININVENTORY,
 };
 
 //All this so I can change the mugshot state in ACS...
@@ -321,13 +334,14 @@ public:
 	void Tick();
 	void ReceivedWeapon (AWeapon *weapon);
 	void FlashItem(const PClass *itemtype);
+	void ShowPop(int popnum);
 	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);
+	void DrawFace(FString &defaultFace, 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);
@@ -349,6 +363,7 @@ private:
 	int mugshotHealth;
 	int chainWiggle;
 	int artiflash;
+	int currentPopup;
 	unsigned int invBarOffset;
 	FBarShader shader_horz_normal;
 	FBarShader shader_horz_reverse;
diff --git a/src/g_shared/sbarinfo_display.cpp b/src/g_shared/sbarinfo_display.cpp
index b65d02511..f98482a03 100644
--- a/src/g_shared/sbarinfo_display.cpp
+++ b/src/g_shared/sbarinfo_display.cpp
@@ -83,13 +83,13 @@ MugShotFrame::~MugShotFrame()
 }
 
 //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)
+FTexture *MugShotFrame::getTexture(FString &defaultFace, FPlayerSkin *skin, int random, int level, int direction, bool usesLevels, bool health2, bool healthspecial, bool directional)
 {
 	int index = !directional ? random % graphic.Size() : direction;
 	if(index > (signed int) (graphic.Size()-1))
 		index = graphic.Size()-1;
 	char* sprite = new char[9];
-	memcpy(sprite, skin->face[0] != 0 ? skin->face : "STF", 3);
+	memcpy(sprite, skin->face[0] != 0 ? skin->face : defaultFace, 3);
 	memcpy(sprite+3, graphic[index], strlen(graphic[index]));
 	sprite[3+strlen(graphic[index])] = '\0';
 	if(usesLevels) //change the last character to the level
@@ -313,6 +313,15 @@ void DSBarInfo::Draw (EHudState state)
 		else if(state == HUD_Fullscreen)
 			doCommands(SBarInfoScript->huds[STBAR_INVENTORYFULLSCREEN]);
 	}
+	if(currentPopup != POP_None)
+	{
+		if(currentPopup == POP_Log)
+			doCommands(SBarInfoScript->huds[STBAR_POPUPLOG]);
+		else if(currentPopup == POP_Keys)
+			doCommands(SBarInfoScript->huds[STBAR_POPUPKEYS]);
+		else if(currentPopup == POP_Status)
+			doCommands(SBarInfoScript->huds[STBAR_POPUPSTATUS]);
+	}
 }
 
 void DSBarInfo::NewGame ()
@@ -409,6 +418,15 @@ void DSBarInfo::FlashItem(const PClass *itemtype)
 	artiflash = 4;
 }
 
+void DSBarInfo::ShowPop(int popnum)
+{
+	DBaseStatusBar::ShowPop(popnum);
+	if(popnum != currentPopup)
+		currentPopup = popnum;
+	else
+		currentPopup = POP_None;
+}
+
 //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.
@@ -543,25 +561,27 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
 				}
 				break;
 			case SBARINFO_DRAWNUMBER:
+			{
+				int value = cmd.value;
 				if(drawingFont != cmd.font)
 				{
 					drawingFont = cmd.font;
 				}
 				if(cmd.flags == DRAWNUMBER_HEALTH)
 				{
-					cmd.value = health;
-					if(cmd.value < 0) //health shouldn't display negatives
+					value = health;
+					if(SBarInfoScript->lowerHealthCap && cmd.value < 0) //health shouldn't display negatives
 					{
-						cmd.value = 0;
+						value = 0;
 					}
 				}
 				else if(cmd.flags == DRAWNUMBER_ARMOR)
 				{
-					cmd.value = armorAmount;
+					value = armorAmount;
 				}
 				else if(cmd.flags == DRAWNUMBER_AMMO1)
 				{
-					cmd.value = ammocount1;
+					value = ammocount1;
 					if(ammo1 == NULL) //no ammo, do not draw
 					{
 						continue;
@@ -569,7 +589,7 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
 				}
 				else if(cmd.flags == DRAWNUMBER_AMMO2)
 				{
-					cmd.value = ammocount2;
+					value = ammocount2;
 					if(ammo2 == NULL) //no ammo, do not draw
 					{
 						continue;
@@ -581,11 +601,11 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
 					AInventory* item = CPlayer->mo->FindInventory(ammo);
 					if(item != NULL)
 					{
-						cmd.value = item->Amount;
+						value = item->Amount;
 					}
 					else
 					{
-						cmd.value = 0;
+						value = 0;
 					}
 				}
 				else if(cmd.flags == DRAWNUMBER_AMMOCAPACITY)
@@ -594,61 +614,64 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
 					AInventory* item = CPlayer->mo->FindInventory(ammo);
 					if(item != NULL)
 					{
-						cmd.value = item->MaxAmount;
+						value = item->MaxAmount;
 					}
 					else
 					{
-						cmd.value = ((AInventory *)GetDefaultByType(ammo))->MaxAmount;
+						value = ((AInventory *)GetDefaultByType(ammo))->MaxAmount;
 					}
 				}
 				else if(cmd.flags == DRAWNUMBER_FRAGS)
-					cmd.value = CPlayer->fragcount;
+					value = CPlayer->fragcount;
 				else if(cmd.flags == DRAWNUMBER_KILLS)
-					cmd.value = level.killed_monsters;
+					value = level.killed_monsters;
 				else if(cmd.flags == DRAWNUMBER_MONSTERS)
-					cmd.value = level.total_monsters;
+					value = level.total_monsters;
 				else if(cmd.flags == DRAWNUMBER_ITEMS)
-					cmd.value = level.found_items;
+					value = level.found_items;
 				else if(cmd.flags == DRAWNUMBER_TOTALITEMS)
-					cmd.value = level.total_items;
+					value = level.total_items;
 				else if(cmd.flags == DRAWNUMBER_SECRETS)
-					cmd.value = level.found_secrets;
+					value = level.found_secrets;
 				else if(cmd.flags == DRAWNUMBER_TOTALSECRETS)
-					cmd.value = level.total_secrets;
+					value = level.total_secrets;
 				else if(cmd.flags == DRAWNUMBER_ARMORCLASS)
 				{
 					AHexenArmor *harmor = CPlayer->mo->FindInventory<AHexenArmor>();
 					if(harmor != NULL)
 					{
-						cmd.value = harmor->Slots[0] + harmor->Slots[1] + 
+						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;
+						value += armor->SavePercent;
 					}
-					cmd.value /= (5*FRACUNIT);
+					value /= (5*FRACUNIT);
 				}
+				else if(cmd.flags == DRAWNUMBER_GLOBALVAR)
+					value = ACS_GlobalVars[cmd.value];
 				else if(cmd.flags == DRAWNUMBER_INVENTORY)
 				{
 					AInventory* item = CPlayer->mo->FindInventory(PClass::FindClass(cmd.string[0]));
 					if(item != NULL)
 					{
-						cmd.value = item->Amount;
+						value = item->Amount;
 					}
 					else
 					{
-						cmd.value = 0;
+						value = 0;
 					}
 				}
 				if(cmd.special3 != -1 && cmd.value <= cmd.special3) //low
-					DrawNumber(cmd.value, cmd.special, cmd.x, cmd.y, cmd.translation2, cmd.special2);
+					DrawNumber(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);
+					DrawNumber(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);
+					DrawNumber(value, cmd.special, cmd.x, cmd.y, cmd.translation, cmd.special2);
 				break;
+			}
 			case SBARINFO_DRAWMUGSHOT:
 			{
 				bool xdth = false;
@@ -657,7 +680,7 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
 					xdth = true;
 				if(cmd.flags & DRAWMUGSHOT_ANIMATEDGODMODE)
 					animatedgodmode = true;
-				DrawFace(cmd.special, xdth, animatedgodmode, cmd.x, cmd.y);
+				DrawFace(cmd.string[0], cmd.special, xdth, animatedgodmode, cmd.x, cmd.y);
 				break;
 			}
 			case SBARINFO_DRAWSELECTEDINVENTORY:
@@ -1000,7 +1023,7 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
 				{
 					drawingFont = cmd.font;
 				}
-				DrawString(cmd.string[0], cmd.x - drawingFont->StringWidth(cmd.string[0]), cmd.y, cmd.translation);
+				DrawString(cmd.string[0], cmd.x - drawingFont->StringWidth(cmd.string[0]), cmd.y, cmd.translation, cmd.special);
 				break;
 			case SBARINFO_DRAWKEYBAR:
 			{
@@ -1046,6 +1069,12 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
 				}
 				break;
 			}
+			case SBARINFO_ASPECTRATIO:
+				if(CheckRatio(screen->GetWidth(), screen->GetHeight()) == cmd.value)
+				{
+					doCommands(cmd.subBlock);
+				}
+				break;
 			case SBARINFO_WEAPONAMMO:
 				if(CPlayer->ReadyWeapon != NULL)
 				{
@@ -1090,6 +1119,30 @@ void DSBarInfo::doCommands(SBarInfoBlock &block)
 					}
 				}
 				break;
+			case SBARINFO_ININVENTORY:
+			{
+				AInventory *item1 = CPlayer->mo->FindInventory(PClass::FindClass(cmd.string[0]));
+				AInventory *item2 = CPlayer->mo->FindInventory(PClass::FindClass(cmd.string[1]));
+				if(cmd.flags & SBARINFOEVENT_AND)
+				{
+					if((item1 != NULL && item2 != NULL) && !(cmd.flags & SBARINFOEVENT_NOT))
+						doCommands(cmd.subBlock);
+					else if((item1 == NULL || item2 == NULL) && (cmd.flags & SBARINFOEVENT_NOT))
+						doCommands(cmd.subBlock);
+				}
+				else if(cmd.flags & SBARINFOEVENT_OR)
+				{
+					if((item1 != NULL || item2 != NULL) && !(cmd.flags & SBARINFOEVENT_NOT))
+						doCommands(cmd.subBlock);
+					else if((item1 == NULL && item2 == NULL) && (cmd.flags & SBARINFOEVENT_NOT))
+						doCommands(cmd.subBlock);
+				}
+				else if((item1 != NULL) && !(cmd.flags & SBARINFOEVENT_NOT))
+					doCommands(cmd.subBlock);
+				else if((item1 == NULL) && (cmd.flags & SBARINFOEVENT_NOT))
+					doCommands(cmd.subBlock);
+				break;
+			}
 		}
 	}
 }
@@ -1102,15 +1155,21 @@ void DSBarInfo::DrawGraphic(FTexture* texture, int x, int y, int flags)
 		x -= (texture->GetWidth()/2)-texture->LeftOffset;
 		y -= (texture->GetHeight()/2)-texture->TopOffset;
 	}
+	x += ST_X;
+	y += ST_Y;
+	int w = texture->GetScaledWidth();
+	int h = texture->GetScaledHeight();
+	screen->VirtualToRealCoordsInt(x, y, w, h, 320, 200, true);
 	if((flags & DRAWIMAGE_TRANSLATABLE))
-		DrawImage(texture, x, y, getTranslation());
+	{
+		screen->DrawTexture(texture, x, y,
+			DTA_DestWidth, w,
+			DTA_DestHeight, h,
+			DTA_Translation, getTranslation(),
+			TAG_DONE);
+	}
 	else
 	{
-		x += ST_X;
-		y += ST_Y;
-		int w = texture->GetScaledWidth();
-		int h = texture->GetScaledHeight();
-		screen->VirtualToRealCoordsInt(x, y, w, h, 320, 200, true);
 		screen->DrawTexture(texture, x, y,
 			DTA_DestWidth, w,
 			DTA_DestHeight, h,
@@ -1142,10 +1201,20 @@ void DSBarInfo::DrawString(const char* str, int x, int y, EColorRange translatio
 		}
 		if(SBarInfoScript->spacingCharacter == '\0') //If we are monospaced lets use the offset
 			x += (character->LeftOffset+1); //ignore x offsets since we adapt to character size
-		DrawImage(character, x, y, drawingFont->GetColorTranslation(translation));
-		x += width + spacing;
+		int rx = x + ST_X;
+		int ry = y + ST_Y;
+		int rw = character->GetScaledWidth();
+		int rh = character->GetScaledHeight();
+		screen->VirtualToRealCoordsInt(rx, ry, rw, rh, 320, 200, true);
+		screen->DrawTexture(character, rx, ry,
+			DTA_DestWidth, rw,
+			DTA_DestHeight, rh,
+			DTA_Translation, drawingFont->GetColorTranslation(translation),
+			TAG_DONE);
 		if(SBarInfoScript->spacingCharacter == '\0')
-			x -= (character->LeftOffset+1);
+			x += width + spacing - (character->LeftOffset+1);
+		else //width gets changed at the call to GetChar()
+			x += drawingFont->GetCharWidth((int) SBarInfoScript->spacingCharacter) + spacing;
 		str++;
 	}
 }
@@ -1165,14 +1234,23 @@ void DSBarInfo::DrawNumber(int num, int len, int x, int y, EColorRange translati
 }
 
 //draws the mug shot
-void DSBarInfo::DrawFace(int accuracy, bool xdth, bool animatedgodmode, int x, int y)
+void DSBarInfo::DrawFace(FString &defaultFace, 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);
+		FTexture *face = currentState->getCurrentFrameTexture(defaultFace, &skins[CPlayer->userinfo.skin], level, angle);
+		x += ST_X;
+		y += ST_Y;
+		int w = face->GetScaledWidth();
+		int h = face->GetScaledHeight();
+		screen->VirtualToRealCoordsInt(x, y, w, h, 320, 200, true);
+		screen->DrawTexture(face, x, y,
+			DTA_DestWidth, w,
+			DTA_DestHeight, h,
+			TAG_DONE);
 	}
 }
 
diff --git a/src/g_shared/sbarinfo_parser.cpp b/src/g_shared/sbarinfo_parser.cpp
index 51be9a513..6d628c485 100644
--- a/src/g_shared/sbarinfo_parser.cpp
+++ b/src/g_shared/sbarinfo_parser.cpp
@@ -57,6 +57,7 @@ static const char *SBarInfoTopLevel[] =
 	"interpolatearmor",
 	"completeborder",
 	"monospacefonts",
+	"lowerhealthcap",
 	"statusbar",
 	"mugshot",
 	NULL
@@ -91,7 +92,9 @@ static const char *SBarInfoRoutineLevel[] =
 	"drawkeybar",
 	"gamemode",
 	"playerclass",
+	"aspectratio",
 	"weaponammo", //event
+	"ininventory",
 	NULL
 };
 
@@ -230,6 +233,18 @@ void SBarInfo::ParseSBarInfo(int lump)
 				}				
 				sc.MustGetToken(';');
 				break;
+			case SBARINFO_LOWERHEALTHCAP:
+				if(sc.CheckToken(TK_False))
+				{
+					lowerHealthCap = false;
+				}
+				else
+				{
+					sc.MustGetToken(TK_True);
+					lowerHealthCap = true;
+				}
+				sc.MustGetToken(';');
+				break;
 			case SBARINFO_STATUSBAR:
 			{
 				if(!baseSet) //If the user didn't explicitly define a base, do so now.
@@ -470,6 +485,14 @@ void SBarInfo::ParseSBarInfoBlock(FScanner &sc, SBarInfoBlock &block)
 						cmd.flags += DRAWNUMBER_TOTALSECRETS;
 					else if(sc.Compare("armorclass"))
 						cmd.flags += DRAWNUMBER_ARMORCLASS;
+					else if(sc.Compare("globalvar"))
+					{
+						cmd.flags += DRAWNUMBER_GLOBALVAR;
+						sc.MustGetToken(TK_IntConst);
+						if(sc.Number < 0 || sc.Number >= NUM_GLOBALVARS)
+							sc.ScriptError("Global variable number out of range: %d", sc.Number);
+						cmd.value = sc.Number;
+					}
 					else
 					{
 						cmd.flags = DRAWNUMBER_INVENTORY;
@@ -738,7 +761,7 @@ void SBarInfo::ParseSBarInfoBlock(FScanner &sc, SBarInfoBlock &block)
 					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
+					if(item == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(item))
 					{
 						sc.ScriptError("'%s' is not a type of inventory item.", sc.String);
 					}
@@ -843,6 +866,11 @@ void SBarInfo::ParseSBarInfoBlock(FScanner &sc, SBarInfoBlock &block)
 				cmd.setString(sc, sc.String, 0, -1, false);
 				sc.MustGetToken(',');
 				this->getCoordinates(sc, cmd);
+				if(sc.CheckToken(',')) //spacing
+				{
+					sc.MustGetToken(TK_IntConst);
+					cmd.special = sc.Number;
+				}
 				sc.MustGetToken(';');
 				break;
 			case SBARINFO_DRAWKEYBAR:
@@ -908,6 +936,21 @@ void SBarInfo::ParseSBarInfoBlock(FScanner &sc, SBarInfoBlock &block)
 			FinishPlayerClass:
 				this->ParseSBarInfoBlock(sc, cmd.subBlock);
 				break;
+			case SBARINFO_ASPECTRATIO:
+				sc.MustGetToken(TK_StringConst);
+				if(sc.Compare("4:3"))
+					cmd.value = ASPECTRATIO_4_3;
+				else if(sc.Compare("16:9"))
+					cmd.value = ASPECTRATIO_16_9;
+				else if(sc.Compare("16:10"))
+					cmd.value = ASPECTRATIO_16_10;
+				else if(sc.Compare("5:4"))
+					cmd.value = ASPECTRATIO_5_4;
+				else
+					sc.ScriptError("Unkown aspect ratio: %s", sc.String);
+				sc.MustGetToken('{');
+				this->ParseSBarInfoBlock(sc, cmd.subBlock);
+				break;
 			case SBARINFO_WEAPONAMMO:
 				sc.MustGetToken(TK_Identifier);
 				if(sc.Compare("not"))
@@ -939,6 +982,39 @@ void SBarInfo::ParseSBarInfoBlock(FScanner &sc, SBarInfoBlock &block)
 				sc.MustGetToken('{');
 				this->ParseSBarInfoBlock(sc, cmd.subBlock);
 				break;
+			case SBARINFO_ININVENTORY:
+			{
+				sc.MustGetToken(TK_Identifier);
+				if(sc.Compare("not"))
+				{
+					cmd.flags += SBARINFOEVENT_NOT;
+					sc.MustGetToken(TK_Identifier);
+				}
+				for(int i = 0;i < 2;i++)
+				{
+					cmd.setString(sc, sc.String, i);
+					const PClass* item = PClass::FindClass(sc.String);
+					if(item == NULL || !RUNTIME_CLASS(AInventory)->IsAncestorOf(item))
+					{
+						sc.ScriptError("'%s' is not a type of inventory item.", sc.String);
+					}
+					if(sc.CheckToken(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);
 	}
@@ -1044,6 +1120,7 @@ void SBarInfo::Init()
 	interpolateHealth = false;
 	interpolateArmor = false;
 	completeBorder = false;
+	lowerHealthCap = true;
 	interpolationSpeed = 8;
 	armorInterpolationSpeed = 8;
 	height = 0;
diff --git a/src/v_collection.cpp b/src/v_collection.cpp
index 8e330c361..55bac6093 100644
--- a/src/v_collection.cpp
+++ b/src/v_collection.cpp
@@ -60,7 +60,13 @@ void FImageCollection::Init (const char **patchNames, int numPatches, int namesp
 
 	for (int i = 0; i < numPatches; ++i)
 	{
-		ImageMap[i] = TexMan.CheckForTexture(patchNames[i], namespc, true);
+		int picnum = TexMan.AddPatch (patchNames[i], namespc, true);
+
+		if (picnum == -1 && namespc != ns_sprites)
+		{
+			picnum = TexMan.AddPatch (patchNames[i], ns_sprites);
+		}
+		ImageMap[i] = picnum;
 	}
 }
 
diff --git a/src/win32/i_input.cpp b/src/win32/i_input.cpp
index 750dc00e5..53973dea5 100644
--- a/src/win32/i_input.cpp
+++ b/src/win32/i_input.cpp
@@ -897,6 +897,9 @@ LRESULT CALLBACK WndProc (HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
 		}
 		return DefWindowProc (hWnd, message, wParam, lParam);
 
+	case WM_ERASEBKGND:
+		return true;
+
 	default:
 		return DefWindowProc (hWnd, message, wParam, lParam);
 	}