Exemple #1
0
// -----------------+
// HWR_DrawTransFill     : draw flat coloured rectangle, with no texture
// -----------------+
void HWR_DrawTransFill(int x, int y, int w, int h, int color, byte alpha)
{
	FOutVector v[4];
	FSurfaceInfo Surf;
	
	//  3--2
	//  | /|
	//  |/ |
	//  0--1
	
	v[0].x = v[3].x = (x - 160.0f)/160.0f;
	v[2].x = v[1].x = ((x+w) - 160.0f)/160.0f;
	v[0].y = v[1].y = -(y - 100.0f)/100.0f;
	v[2].y = v[3].y = -((y+h) - 100.0f)/100.0f;

	v[0].z = v[1].z = v[2].z = v[3].z = 1.0f;
	
	v[0].sow = v[3].sow = 0.0f;
	v[2].sow = v[1].sow = 1.0f;
	v[0].tow = v[1].tow = 0.0f;
	v[2].tow = v[3].tow = 1.0f;
	
	Surf.FlatColor = V_GetColor(color);
	Surf.FlatColor.s.alpha = alpha;
	
	GL_DrawPolygon(&Surf, v, 4,
				   PF_Modulated|PF_NoTexture|PF_NoDepthTest|PF_Translucent, 0);
}
Exemple #2
0
// -----------------+
// HWR_drawAMline   : draw a line of the automap (the clipping is already done in automap code)
// Arg              : color is a RGB 888 value
// -----------------+
void HWR_drawAMline(const fline_t *fl, int color)
{
	F2DCoord v1, v2;
	RGBA_t color_rgba;

	color_rgba = V_GetColor(color);

	v1.x = ((float)fl->a.x-(vid.width/2.0f))*(2.0f/vid.width);
	v1.y = ((float)fl->a.y-(vid.height/2.0f))*(2.0f/vid.height);

	v2.x = ((float)fl->b.x-(vid.width/2.0f))*(2.0f/vid.width);
	v2.y = ((float)fl->b.y-(vid.height/2.0f))*(2.0f/vid.height);

	GL_Draw2DLine(&v1, &v2, color_rgba);
}
Exemple #3
0
//===========================================================================
// 
//	Reads glow definitions from GLDEFS
//
//===========================================================================
void gl_InitGlow(FScanner &sc)
{
	sc.MustGetStringName("{");
	while (!sc.CheckString("}"))
	{
		sc.MustGetString();
		if (sc.Compare("FLATS"))
		{
			sc.MustGetStringName("{");
			while (!sc.CheckString("}"))
			{
				sc.MustGetString();
				FTextureID flump=TexMan.CheckForTexture(sc.String, FTexture::TEX_Flat,FTextureManager::TEXMAN_TryAny);
				FTexture *tex = TexMan[flump];
				if (tex) tex->gl_info.bGlowing = tex->gl_info.bFullbright = true;
			}
		}
		else if (sc.Compare("WALLS"))
		{
			sc.MustGetStringName("{");
			while (!sc.CheckString("}"))
			{
				sc.MustGetString();
				FTextureID flump=TexMan.CheckForTexture(sc.String, FTexture::TEX_Wall,FTextureManager::TEXMAN_TryAny);
				FTexture *tex = TexMan[flump];
				if (tex) tex->gl_info.bGlowing = tex->gl_info.bFullbright = true;
			}
		}
		else if (sc.Compare("TEXTURE"))
		{
			sc.SetCMode(true);
			sc.MustGetString();
			FTextureID flump=TexMan.CheckForTexture(sc.String, FTexture::TEX_Flat,FTextureManager::TEXMAN_TryAny);
			FTexture *tex = TexMan[flump];
			sc.MustGetStringName(",");
			sc.MustGetString();
			PalEntry color = V_GetColor(NULL, sc.String);
			//sc.MustGetStringName(",");
			//sc.MustGetNumber();
			if (sc.CheckString(","))
			{
				if (sc.CheckNumber())
				{
					if (tex) tex->gl_info.GlowHeight = sc.Number;
					if (!sc.CheckString(",")) goto skip_fb;
				}

				sc.MustGetStringName("fullbright");
				if (tex) tex->gl_info.bFullbright = true;
			}
		skip_fb:
			sc.SetCMode(false);

			if (tex && color != 0)
			{
				tex->gl_info.bGlowing = true;
				tex->gl_info.GlowColor = color;
			}
		}
	}
}
Exemple #4
0
void FMultiPatchTexture::ParsePatch(FScanner &sc, TexPart & part, TexInit &init)
{
	FString patchname;
	int Mirror = 0;
	sc.MustGetString();

	init.TexName = sc.String;
	sc.MustGetStringName(",");
	sc.MustGetNumber();
	part.OriginX = sc.Number;
	sc.MustGetStringName(",");
	sc.MustGetNumber();
	part.OriginY = sc.Number;

	if (sc.CheckString("{"))
	{
		while (!sc.CheckString("}"))
		{
			sc.MustGetString();
			if (sc.Compare("flipx"))
			{
				Mirror |= 1;
			}
			else if (sc.Compare("flipy"))
			{
				Mirror |= 2;
			}
			else if (sc.Compare("rotate"))
			{
				sc.MustGetNumber();
				sc.Number = (((sc.Number + 90)%360)-90);
 				if (sc.Number != 0 && sc.Number !=90 && sc.Number != 180 && sc.Number != -90)
 				{
					sc.ScriptError("Rotation must be a multiple of 90 degrees.");
				}
				part.Rotate = (sc.Number / 90) & 3;
			}
			else if (sc.Compare("Translation"))
			{
				int match;

				bComplex = true;
				if (part.Translation != NULL) delete part.Translation;
				part.Translation = NULL;
				part.Blend = 0;
				static const char *maps[] = { "inverse", "gold", "red", "green", "blue", NULL };
				sc.MustGetString();

				match = sc.MatchString(maps);
				if (match >= 0)
				{
					part.Blend = BLEND_SPECIALCOLORMAP1 + match;
				}
				else if (sc.Compare("ICE"))
				{
					part.Blend = BLEND_ICEMAP;
				}
				else if (sc.Compare("DESATURATE"))
				{
					sc.MustGetStringName(",");
					sc.MustGetNumber();
					part.Blend = BLEND_DESATURATE1 + clamp(sc.Number-1, 0, 30);
				}
				else
				{
					sc.UnGet();
					part.Translation = new FRemapTable;
					part.Translation->MakeIdentity();
					do
					{
						sc.MustGetString();
						part.Translation->AddToTranslation(sc.String);
					}
					while (sc.CheckString(","));
				}

			}
			else if (sc.Compare("Colormap"))
			{
				float r1,g1,b1;
				float r2,g2,b2;

				sc.MustGetFloat();
				r1 = (float)sc.Float;
				sc.MustGetStringName(",");
				sc.MustGetFloat();
				g1 = (float)sc.Float;
				sc.MustGetStringName(",");
				sc.MustGetFloat();
				b1 = (float)sc.Float;
				if (!sc.CheckString(","))
				{
					part.Blend = AddSpecialColormap(0,0,0, r1, g1, b1);
				}
				else
				{
					sc.MustGetFloat();
					r2 = (float)sc.Float;
					sc.MustGetStringName(",");
					sc.MustGetFloat();
					g2 = (float)sc.Float;
					sc.MustGetStringName(",");
					sc.MustGetFloat();
					b2 = (float)sc.Float;
					part.Blend = AddSpecialColormap(r1, g1, b1, r2, g2, b2);
				}
			}
			else if (sc.Compare("Blend"))
			{
				bComplex = true;
				if (part.Translation != NULL) delete part.Translation;
				part.Translation = NULL;
				part.Blend = 0;

				if (!sc.CheckNumber())
				{
					sc.MustGetString();
					part.Blend = V_GetColor(NULL, sc);
				}
				else
				{
					int r,g,b;

					r = sc.Number;
					sc.MustGetStringName(",");
					sc.MustGetNumber();
					g = sc.Number;
					sc.MustGetStringName(",");
					sc.MustGetNumber();
					b = sc.Number;
					//sc.MustGetStringName(","); This was never supposed to be here. 
					part.Blend = MAKERGB(r, g, b);
				}
				// Blend.a may never be 0 here.
				if (sc.CheckString(","))
				{
					sc.MustGetFloat();
					if (sc.Float > 0.f)
						part.Blend.a = clamp<int>(int(sc.Float*255), 1, 254);
					else
						part.Blend = 0;
				}
				else part.Blend.a = 255;
			}
			else if (sc.Compare("alpha"))
			{
				sc.MustGetFloat();
				part.Alpha = clamp<blend_t>(int(sc.Float * BLENDUNIT), 0, BLENDUNIT);
				// bComplex is not set because it is only needed when the style is not OP_COPY.
			}
			else if (sc.Compare("style"))
			{
				static const char *styles[] = {"copy", "translucent", "add", "subtract", "reversesubtract", "modulate", "copyalpha", "copynewalpha", "overlay", NULL };
				sc.MustGetString();
				part.op = sc.MustMatchString(styles);
				bComplex |= (part.op != OP_COPY);
				bTranslucentPatches = bComplex;
			}
			else if (sc.Compare("useoffsets"))
			{
				init.UseOffsets = true;
			}
		}
	}
	if (Mirror & 2)
	{
		part.Rotate = (part.Rotate + 2) & 3;
		Mirror ^= 1;
	}
	if (Mirror & 1)
	{
		part.Rotate |= 4;
	}
}
static void ParseListMenuBody(FScanner &sc, FListMenuDescriptor *desc)
{
	sc.MustGetStringName("{");
	while (!sc.CheckString("}"))
	{
		sc.MustGetString();
		if (sc.Compare("else"))
		{
			SkipSubBlock(sc);
		}
		else if (sc.Compare("ifgame"))
		{
			if (!CheckSkipGameBlock(sc))
			{
				// recursively parse sub-block
				ParseListMenuBody(sc, desc);
			}
		}
		else if (sc.Compare("ifoption"))
		{
			if (!CheckSkipOptionBlock(sc))
			{
				// recursively parse sub-block
				ParseListMenuBody(sc, desc);
			}
		}
		else if (sc.Compare("Class"))
		{
			sc.MustGetString();
			const PClass *cls = PClass::FindClass(sc.String);
			if (cls == NULL || !cls->IsDescendantOf(RUNTIME_CLASS(DListMenu)))
			{
				sc.ScriptError("Unknown menu class '%s'", sc.String);
			}
			desc->mClass = cls;
		}
		else if (sc.Compare("Selector"))
		{
			sc.MustGetString();
			desc->mSelector = TexMan.CheckForTexture(sc.String, FTexture::TEX_MiscPatch);
			sc.MustGetStringName(",");
			sc.MustGetNumber();
			desc->mSelectOfsX = sc.Number;
			sc.MustGetStringName(",");
			sc.MustGetNumber();
			desc->mSelectOfsY = sc.Number;
		}
		else if (sc.Compare("Linespacing"))
		{
			sc.MustGetNumber();
			desc->mLinespacing = sc.Number;
		}
		else if (sc.Compare("Position"))
		{
			sc.MustGetNumber();
			desc->mXpos = sc.Number;
			sc.MustGetStringName(",");
			sc.MustGetNumber();
			desc->mYpos = sc.Number;
		}
		else if (sc.Compare("Centermenu"))
		{
			desc->mCenter = true;
		}
		else if (sc.Compare("MouseWindow"))
		{
			sc.MustGetNumber();
			desc->mWLeft = sc.Number;
			sc.MustGetStringName(",");
			sc.MustGetNumber();
			desc->mWRight = sc.Number;
		}
		else if (sc.Compare("StaticPatch") || sc.Compare("StaticPatchCentered"))
		{
			bool centered = sc.Compare("StaticPatchCentered");
			sc.MustGetNumber();
			int x = sc.Number;
			sc.MustGetStringName(",");
			sc.MustGetNumber();
			int y = sc.Number;
			sc.MustGetStringName(",");
			sc.MustGetString();
			FTextureID tex = TexMan.CheckForTexture(sc.String, FTexture::TEX_MiscPatch);

			FListMenuItem *it = new FListMenuItemStaticPatch(x, y, tex, centered);
			desc->mItems.Push(it);
		}
		else if (sc.Compare("StaticText") || sc.Compare("StaticTextCentered"))
		{
			bool centered = sc.Compare("StaticTextCentered");
			sc.MustGetNumber();
			int x = sc.Number;
			sc.MustGetStringName(",");
			sc.MustGetNumber();
			int y = sc.Number;
			sc.MustGetStringName(",");
			sc.MustGetString();
			FListMenuItem *it = new FListMenuItemStaticText(x, y, sc.String, desc->mFont, desc->mFontColor, centered);
			desc->mItems.Push(it);
		}
		else if (sc.Compare("PatchItem"))
		{
			sc.MustGetString();
			FTextureID tex = TexMan.CheckForTexture(sc.String, FTexture::TEX_MiscPatch);
			sc.MustGetStringName(",");
			sc.MustGetString();
			int hotkey = sc.String[0];
			sc.MustGetStringName(",");
			sc.MustGetString();
			FName action = sc.String;
			int param = 0;
			if (sc.CheckString(","))
			{
				sc.MustGetNumber();
				param = sc.Number;
			}

			FListMenuItem *it = new FListMenuItemPatch(desc->mXpos, desc->mYpos, desc->mLinespacing, hotkey, tex, action, param);
			desc->mItems.Push(it);
			desc->mYpos += desc->mLinespacing;
			if (desc->mSelectedItem == -1) desc->mSelectedItem = desc->mItems.Size()-1;
		}
		else if (sc.Compare("TextItem"))
		{
			sc.MustGetString();
			FString text = sc.String;
			sc.MustGetStringName(",");
			sc.MustGetString();
			int hotkey = sc.String[0];
			sc.MustGetStringName(",");
			sc.MustGetString();
			FName action = sc.String;
			int param = 0;
			if (sc.CheckString(","))
			{
				sc.MustGetNumber();
				param = sc.Number;
			}

			FListMenuItem *it = new FListMenuItemText(desc->mXpos, desc->mYpos, desc->mLinespacing, hotkey, text, desc->mFont, desc->mFontColor, desc->mFontColor2, action, param);
			desc->mItems.Push(it);
			desc->mYpos += desc->mLinespacing;
			if (desc->mSelectedItem == -1) desc->mSelectedItem = desc->mItems.Size()-1;

		}
		else if (sc.Compare("Font"))
		{
			sc.MustGetString();
			FFont *newfont = V_GetFont(sc.String);
			if (newfont != NULL) desc->mFont = newfont;
			if (sc.CheckString(","))
			{
				sc.MustGetString();
				desc->mFontColor2 = desc->mFontColor = V_FindFontColor((FName)sc.String);
				if (sc.CheckString(","))
				{
					sc.MustGetString();
					desc->mFontColor2 = V_FindFontColor((FName)sc.String);
				}
			}
			else
			{
				desc->mFontColor = OptionSettings.mFontColor;
				desc->mFontColor2 = OptionSettings.mFontColorValue;
			}
		}
		else if (sc.Compare("NetgameMessage"))
		{
			sc.MustGetString();
			desc->mNetgameMessage = sc.String;
		}
		else if (sc.Compare("PlayerDisplay"))
		{
			bool noportrait = false;
			FName action = NAME_None;
			sc.MustGetNumber();
			int x = sc.Number;
			sc.MustGetStringName(",");
			sc.MustGetNumber();
			int y = sc.Number;
			sc.MustGetStringName(",");
			sc.MustGetString();
			PalEntry c1 = V_GetColor(NULL, sc.String);
			sc.MustGetStringName(",");
			sc.MustGetString();
			PalEntry c2 = V_GetColor(NULL, sc.String);
			if (sc.CheckString(","))
			{
				sc.MustGetNumber();
				noportrait = !!sc.Number;
				if (sc.CheckString(","))
				{
					sc.MustGetString();
					action = sc.String;
				}
			}
			FListMenuItemPlayerDisplay *it = new FListMenuItemPlayerDisplay(desc, x, y, c1, c2, noportrait, action);
			desc->mItems.Push(it);
		}
		else if (sc.Compare("PlayerNameBox"))
		{
			sc.MustGetString();
			FString text = sc.String;
			sc.MustGetStringName(",");
			sc.MustGetNumber();
			int ofs = sc.Number;
			sc.MustGetStringName(",");
			sc.MustGetString();
			FListMenuItem *it = new FPlayerNameBox(desc->mXpos, desc->mYpos, desc->mLinespacing, ofs, text, desc->mFont, desc->mFontColor, sc.String);
			desc->mItems.Push(it);
			desc->mYpos += desc->mLinespacing;
			if (desc->mSelectedItem == -1) desc->mSelectedItem = desc->mItems.Size()-1;
		}
		else if (sc.Compare("ValueText"))
		{
			sc.MustGetString();
			FString text = sc.String;
			sc.MustGetStringName(",");
			sc.MustGetString();
			FName action = sc.String;
			FName values;
			if (sc.CheckString(","))
			{
				sc.MustGetString();
				values = sc.String;
			}
			FListMenuItem *it = new FValueTextItem(desc->mXpos, desc->mYpos, desc->mLinespacing, text, desc->mFont, desc->mFontColor, desc->mFontColor2, action, values);
			desc->mItems.Push(it);
			desc->mYpos += desc->mLinespacing;
			if (desc->mSelectedItem == -1) desc->mSelectedItem = desc->mItems.Size()-1;
		}
		else if (sc.Compare("Slider"))
		{
			sc.MustGetString();
			FString text = sc.String;
			sc.MustGetStringName(",");
			sc.MustGetString();
			FString action = sc.String;
			sc.MustGetStringName(",");
			sc.MustGetNumber();
			int min = sc.Number;
			sc.MustGetStringName(",");
			sc.MustGetNumber();
			int max = sc.Number;
			sc.MustGetStringName(",");
			sc.MustGetNumber();
			int step = sc.Number;
			FListMenuItem *it = new FSliderItem(desc->mXpos, desc->mYpos, desc->mLinespacing, text, desc->mFont, desc->mFontColor, action, min, max, step);
			desc->mItems.Push(it);
			desc->mYpos += desc->mLinespacing;
			if (desc->mSelectedItem == -1) desc->mSelectedItem = desc->mItems.Size()-1;
		}
		else
		{
			sc.ScriptError("Unknown keyword '%s'", sc.String);
		}
	}
}
Exemple #6
0
void FTeam::ParseTeamDefinition (FScanner &Scan)
{
	FTeam Team;
	int valid = -1;
	Scan.MustGetString ();
	Team.m_Name = Scan.String;
	Scan.MustGetStringName ("{");

	while (!Scan.CheckString ("}"))
	{
		Scan.MustGetString ();

		switch (Scan.MatchString (TeamInfoOptions))
		{
		case TEAMINFO_Game:
			Scan.MustGetString ();
			if (Scan.Compare("Any")) valid = 1;
			else if (CheckGame(Scan.String, false)) valid = 1;
			else if (valid == -1) valid = 0;
			break;

		case TEAMINFO_PlayerColor:
			Scan.MustGetString ();
			Team.m_iPlayerColor = V_GetColor (NULL, Scan.String);
			break;

		case TEAMINFO_TextColor:
			Scan.MustGetString ();
			Team.m_TextColor.AppendFormat ("[%s]", Scan.String);
			break;

		case TEAMINFO_Logo:
			Scan.MustGetString ();
			Team.m_Logo = Scan.String;
			break;

		case TEAMINFO_AllowCustomPlayerColor:
			Team.m_bAllowCustomPlayerColor = true;
			break;

		case TEAMINFO_PlayerStartThingNumber:
			Scan.MustGetNumber ();
			break;

		case TEAMINFO_RailColor:
		case TEAMINFO_FlagItem:
		case TEAMINFO_SkullItem:
		case TEAMINFO_SmallFlagHUDIcon:
		case TEAMINFO_SmallSkullHUDIcon:
		case TEAMINFO_LargeFlagHUDIcon:
		case TEAMINFO_LargeSkullHUDIcon:
		case TEAMINFO_WinnerPic:
		case TEAMINFO_LoserPic:
		case TEAMINFO_WinnerTheme:
		case TEAMINFO_LoserTheme:
			Scan.MustGetString ();
			break;

		default:
			Scan.ScriptError ("ParseTeamDefinition: Unknown team option '%s'.\n", Scan.String);
			break;
		}
	}

	if (valid) Teams.Push (Team);
}
FxExpression *ParseParameter(FScanner &sc, PClassActor *cls, PType *type, bool constant)
{
	FxExpression *x = NULL;
	int v;

	if (type == TypeSound)
	{
		sc.MustGetString();
		x = new FxConstant(FSoundID(sc.String), sc);
	}
	else if (type == TypeBool || type == TypeSInt32 || type == TypeFloat64)
	{
		x = ParseExpression (sc, cls, constant);
		if (constant && !x->isConstant())
		{
			sc.ScriptMessage("Default parameter must be constant.");
			FScriptPosition::ErrorCounter++;
		}
		// Do automatic coercion between bools, ints and floats.
		if (type == TypeBool)
		{
			x = new FxBoolCast(x);
		}
		else if (type == TypeSInt32)
		{
			x = new FxIntCast(x);
		}
		else
		{
			x = new FxFloatCast(x);
		}
	}
	else if (type == TypeName || type == TypeString)
	{
		sc.SetEscape(true);
		sc.MustGetString();
		sc.SetEscape(false);
		if (type == TypeName)
		{
			x = new FxConstant(sc.String[0] ? FName(sc.String) : NAME_None, sc);
		}
		else
		{
			x = new FxConstant(strbin1(sc.String), sc);
		}
	}
	else if (type == TypeColor)
	{
		sc.MustGetString ();
		if (sc.Compare("none"))
		{
			v = -1;
		}
		else if (sc.Compare(""))
		{
			v = 0;
		}
		else
		{
			int c = V_GetColor (NULL, sc.String);
			// 0 needs to be the default so we have to mark the color.
			v = MAKEARGB(1, RPART(c), GPART(c), BPART(c));
		}
		ExpVal val;
		val.Type = TypeColor;
		val.Int = v;
		x = new FxConstant(val, sc);
	}
	else if (type == TypeState)
	{
		// This forces quotation marks around the state name.
		sc.MustGetToken(TK_StringConst);
		if (sc.String[0] == 0 || sc.Compare("None"))
		{
			x = new FxConstant((FState*)NULL, sc);
		}
		else if (sc.Compare("*"))
		{
			if (constant) 
			{
				x = new FxConstant((FState*)(intptr_t)-1, sc);
			}
			else sc.ScriptError("Invalid state name '*'");
		}
		else
		{
			x = new FxMultiNameState(sc.String, sc);
		}
	}
	else if (type->GetClass() == RUNTIME_CLASS(PClassPointer))
	{	// Actor name
		sc.SetEscape(true);
		sc.MustGetString();
		sc.SetEscape(false);
		x = new FxClassTypeCast(static_cast<PClassPointer *>(type)->ClassRestriction, new FxConstant(FName(sc.String), sc));
	}
	else
	{
		assert(false && "Unknown parameter type");
		x = NULL;
	}
	return x;
}
Exemple #8
0
void FIWadManager::ParseIWadInfo(const char *fn, const char *data, int datasize)
{
	FScanner sc;

	sc.OpenMem("IWADINFO", data, datasize);
	while (sc.GetString())
	{
		if (sc.Compare("IWAD"))
		{
			FIWADInfo *iwad = &mIWads[mIWads.Reserve(1)];
			sc.MustGetStringName("{");
			while (!sc.CheckString("}"))
			{
				sc.MustGetString();
				if (sc.Compare("Name"))
				{
					sc.MustGetStringName("=");
					sc.MustGetString();
					iwad->Name = sc.String;
				}
				else if (sc.Compare("Autoname"))
				{
					sc.MustGetStringName("=");
					sc.MustGetString();
					iwad->Autoname = sc.String;
				}
				else if (sc.Compare("Config"))
				{
					sc.MustGetStringName("=");
					sc.MustGetString();
					iwad->Configname = sc.String;
				}
				else if (sc.Compare("Game"))
				{
					sc.MustGetStringName("=");
					sc.MustGetString();
					if (sc.Compare("Doom")) iwad->gametype = GAME_Doom;
					else if (sc.Compare("Heretic")) iwad->gametype = GAME_Heretic;
					else if (sc.Compare("Hexen")) iwad->gametype = GAME_Hexen;
					else if (sc.Compare("Strife")) iwad->gametype = GAME_Strife;
					else if (sc.Compare("Chex")) iwad->gametype = GAME_Chex;
					else sc.ScriptError(NULL);
				}
				else if (sc.Compare("Mapinfo"))
				{
					sc.MustGetStringName("=");
					sc.MustGetString();
					iwad->MapInfo = sc.String;
				}
				else if (sc.Compare("Compatibility"))
				{
					sc.MustGetStringName("=");
					do
					{
						sc.MustGetString();
						if(sc.Compare("NoTextcolor")) iwad->flags |= GI_NOTEXTCOLOR;
						else if(sc.Compare("Poly1")) iwad->flags |= GI_COMPATPOLY1;
						else if(sc.Compare("Poly2")) iwad->flags |= GI_COMPATPOLY2;
						else if(sc.Compare("Shareware")) iwad->flags |= GI_SHAREWARE;
						else if(sc.Compare("Teaser2")) iwad->flags |= GI_TEASER2;
						else if(sc.Compare("Extended")) iwad->flags |= GI_MENUHACK_EXTENDED;
						else if(sc.Compare("Shorttex")) iwad->flags |= GI_COMPATSHORTTEX;
						else if(sc.Compare("Stairs")) iwad->flags |= GI_COMPATSTAIRS;
						else sc.ScriptError(NULL);
					}
					while (sc.CheckString(","));
				}
				else if (sc.Compare("MustContain"))
				{
					sc.MustGetStringName("=");
					do
					{
						sc.MustGetString();
						iwad->Lumps.Push(FString(sc.String));
					}
					while (sc.CheckString(","));
				}
				else if (sc.Compare("BannerColors"))
				{
					sc.MustGetStringName("=");
					sc.MustGetString();
					iwad->FgColor = V_GetColor(NULL, sc.String);
					sc.MustGetStringName(",");
					sc.MustGetString();
					iwad->BkColor = V_GetColor(NULL, sc.String);
				}
				else if (sc.Compare("Load"))
				{
					sc.MustGetStringName("=");
					do
					{
						sc.MustGetString();
						iwad->Load.Push(FString(sc.String));
					}
					while (sc.CheckString(","));
				}
				else if (sc.Compare("Required"))
				{
					sc.MustGetStringName("=");
					sc.MustGetString();
					iwad->Required = sc.String;
				}
				else
				{
					sc.ScriptError("Unknown keyword '%s'", sc.String);
				}
			}
		}
		else if (sc.Compare("NAMES"))
		{
			sc.MustGetStringName("{");
			mIWadNames.Push(FString());
			while (!sc.CheckString("}"))
			{
				sc.MustGetString();
				FString wadname = sc.String;
#if defined(_WIN32) || defined(__APPLE__) // Turns out Mac OS X is case insensitive.
				mIWadNames.Push(wadname);
#else
				// check for lowercase, uppercased first letter and full uppercase on Linux etc.
				wadname.ToLower();
				mIWadNames.Push(wadname);
				wadname.LockBuffer()[0] = toupper(wadname[0]);
				wadname.UnlockBuffer();
				mIWadNames.Push(wadname);
				wadname.ToUpper();
				mIWadNames.Push(wadname);
#endif
			}
		}
	}
}
//==========================================================================
//
// ParseStates
// parses a state block
//
//==========================================================================
int ParseStates(FActorInfo * actor, AActor * defaults, Baggage &bag)
{
	FString statestring;
	intptr_t count = 0;
	FState state;
	FState * laststate = NULL;
	intptr_t lastlabel = -1;
	int minrequiredstate = -1;

	SC_MustGetStringName ("{");
	SC_SetEscape(false);	// disable escape sequences in the state parser
	while (!SC_CheckString ("}") && !sc_End)
	{
		memset(&state,0,sizeof(state));
		statestring = ParseStateString();
		if (!statestring.CompareNoCase("GOTO"))
		{
do_goto:	
			statestring = ParseStateString();
			if (SC_CheckString ("+"))
			{
				SC_MustGetNumber ();
				statestring += '+';
				statestring += sc_String;
			}
			// copy the text - this must be resolved later!
			if (laststate != NULL)
			{ // Following a state definition: Modify it.
				laststate->NextState = (FState*)copystring(statestring);	
			}
			else if (lastlabel >= 0)
			{ // Following a label: Retarget it.
				RetargetStates (count+1, statestring);
			}
			else
			{
				SC_ScriptError("GOTO before first state");
			}
		}
		else if (!statestring.CompareNoCase("STOP"))
		{
do_stop:
			if (laststate!=NULL)
			{
				laststate->NextState=(FState*)-1;
			}
			else if (lastlabel >=0)
			{
				RetargetStates (count+1, NULL);
			}
			else
			{
				SC_ScriptError("STOP before first state");
				continue;
			}
		}
		else if (!statestring.CompareNoCase("WAIT") || !statestring.CompareNoCase("FAIL"))
		{
			if (!laststate) 
			{
				SC_ScriptError("%s before first state", sc_String);
				continue;
			}
			laststate->NextState=(FState*)-2;
		}
		else if (!statestring.CompareNoCase("LOOP"))
		{
			if (!laststate) 
			{
				SC_ScriptError("LOOP before first state");
				continue;
			}
			laststate->NextState=(FState*)(lastlabel+1);
		}
		else
		{
			const char * statestrp;

			SC_MustGetString();
			if (SC_Compare (":"))
			{
				laststate = NULL;
				do
				{
					lastlabel = count;
					AddState(statestring, (FState *) (count+1));
					statestring = ParseStateString();
					if (!statestring.CompareNoCase("GOTO"))
					{
						goto do_goto;
					}
					else if (!statestring.CompareNoCase("STOP"))
					{
						goto do_stop;
					}
					SC_MustGetString ();
				} while (SC_Compare (":"));
//				continue;
			}

			SC_UnGet ();

			if (statestring.Len() != 4)
			{
				SC_ScriptError ("Sprite names must be exactly 4 characters\n");
			}

			memcpy(state.sprite.name, statestring, 4);
			state.Misc1=state.Misc2=0;
			state.ParameterIndex=0;
			SC_MustGetString();
			statestring = (sc_String+1);
			statestrp = statestring;
			state.Frame=(*sc_String&223)-'A';
			if ((*sc_String&223)<'A' || (*sc_String&223)>']')
			{
				SC_ScriptError ("Frames must be A-Z, [, \\, or ]");
				state.Frame=0;
			}

			SC_MustGetNumber();
			sc_Number++;
			state.Tics=sc_Number&255;
			state.Misc1=(sc_Number>>8)&255;
			if (state.Misc1) state.Frame|=SF_BIGTIC;

			while (SC_GetString() && !sc_Crossed)
			{
				if (SC_Compare("BRIGHT")) 
				{
					state.Frame|=SF_FULLBRIGHT;
					continue;
				}
				if (SC_Compare("OFFSET"))
				{
					if (state.Frame&SF_BIGTIC)
					{
						SC_ScriptError("You cannot use OFFSET with a state duration larger than 254!");
					}
					// specify a weapon offset
					SC_MustGetStringName("(");
					SC_MustGetNumber();
					state.Misc1=sc_Number;
					SC_MustGetStringName (",");
					SC_MustGetNumber();
					state.Misc2=sc_Number;
					SC_MustGetStringName(")");
					continue;
				}

				// Make the action name lowercase to satisfy the gperf hashers
				strlwr (sc_String);

				int minreq=count;
				if (DoActionSpecials(state, !statestring.IsEmpty(), &minreq, bag))
				{
					if (minreq>minrequiredstate) minrequiredstate=minreq;
					goto endofstate;
				}

				PSymbol *sym = bag.Info->Class->Symbols.FindSymbol (FName(sc_String, true), true);
				if (sym != NULL && sym->SymbolType == SYM_ActionFunction)
				{
					PSymbolActionFunction *afd = static_cast<PSymbolActionFunction *>(sym);
					state.Action = afd->Function;
					if (!afd->Arguments.IsEmpty())
					{
						const char *params = afd->Arguments.GetChars();
						int numparams = (int)afd->Arguments.Len();
				
						int v;

						if (!islower(*params))
						{
							SC_MustGetStringName("(");
						}
						else
						{
							if (!SC_CheckString("(")) goto endofstate;
						}
						
						int paramindex = PrepareStateParameters(&state, numparams);
						int paramstart = paramindex;
						bool varargs = params[numparams - 1] == '+';

						if (varargs)
						{
							StateParameters[paramindex++] = 0;
						}

						while (*params)
						{
							switch(*params)
							{
							case 'I':
							case 'i':		// Integer
								SC_MustGetNumber();
								v=sc_Number;
								break;

							case 'F':
							case 'f':		// Fixed point
								SC_MustGetFloat();
								v=fixed_t(sc_Float*FRACUNIT);
								break;


							case 'S':
							case 's':		// Sound name
								SC_MustGetString();
								v=S_FindSound(sc_String);
								break;

							case 'M':
							case 'm':		// Actor name
							case 'T':
							case 't':		// String
								SC_SetEscape(true);
								SC_MustGetString();
								SC_SetEscape(false);
								v = (int)(sc_String[0] ? FName(sc_String) : NAME_None);
								break;

							case 'L':
							case 'l':		// Jump label

								if (SC_CheckNumber())
								{
									if (strlen(statestring)>0)
									{
										SC_ScriptError("You cannot use A_Jump commands with a jump index on multistate definitions\n");
									}

									v=sc_Number;
									if (v<1)
									{
										SC_ScriptError("Negative jump offsets are not allowed");
									}

									{
										int minreq=count+v;
										if (minreq>minrequiredstate) minrequiredstate=minreq;
									}
								}
								else
								{
									if (JumpParameters.Size()==0) JumpParameters.Push(NAME_None);

									v = -(int)JumpParameters.Size();
									// This forces quotation marks around the state name.
									SC_MustGetToken(TK_StringConst);
									FString statestring = sc_String; // ParseStateString();
									const PClass *stype=NULL;
									int scope = statestring.IndexOf("::");
									if (scope >= 0)
									{
										FName scopename = FName(statestring, scope, false);
										if (scopename == NAME_Super)
										{
											// Super refers to the direct superclass
											scopename = actor->Class->ParentClass->TypeName;
										}
										JumpParameters.Push(scopename);
										statestring = statestring.Right(statestring.Len()-scope-2);

										stype = PClass::FindClass (scopename);
										if (stype == NULL)
										{
											SC_ScriptError ("%s is an unknown class.", scopename.GetChars());
										}
										if (!stype->IsDescendantOf (RUNTIME_CLASS(AActor)))
										{
											SC_ScriptError ("%s is not an actor class, so it has no states.", stype->TypeName.GetChars());
										}
										if (!stype->IsAncestorOf (actor->Class))
										{
											SC_ScriptError ("%s is not derived from %s so cannot access its states.",
												actor->Class->TypeName.GetChars(), stype->TypeName.GetChars());
										}
									}
									else
									{
										// No class name is stored. This allows 'virtual' jumps to
										// labels in subclasses.
										// It also means that the validity of the given state cannot
										// be checked here.
										JumpParameters.Push(NAME_None);
									}
									TArray<FName> names;
									MakeStateNameList(statestring, &names);

									if (stype != NULL)
									{
										if (!stype->ActorInfo->FindState(names.Size(), &names[0]))
										{
											SC_ScriptError("Jump to unknown state '%s' in class '%s'",
												statestring.GetChars(), stype->TypeName.GetChars());
										}
									}
									JumpParameters.Push((ENamedName)names.Size());
									for(unsigned i=0;i<names.Size();i++)
									{
										JumpParameters.Push(names[i]);
									}
									// No offsets here. The point of jumping to labels is to avoid such things!
								}

								break;

							case 'C':
							case 'c':		// Color
								SC_MustGetString ();
								if (SC_Compare("none"))
								{
									v = -1;
								}
								else
								{
									int c = V_GetColor (NULL, sc_String);
									// 0 needs to be the default so we have to mark the color.
									v = MAKEARGB(1, RPART(c), GPART(c), BPART(c));
								}
								break;

							case 'X':
							case 'x':
								v = ParseExpression (false, bag.Info->Class);
								break;

							case 'Y':
							case 'y':
								v = ParseExpression (true, bag.Info->Class);
								break;

							default:
								assert(false);
								v = -1;
								break;
							}
							StateParameters[paramindex++] = v;
							params++;
							if (varargs)
							{
								StateParameters[paramstart]++;
							}
							if (*params)
							{
								if (*params == '+')
								{
									if (SC_CheckString(")"))
									{
										goto endofstate;
									}
									params--;
									v = 0;
									StateParameters.Push(v);
								}
								else if ((islower(*params) || *params=='!') && SC_CheckString(")"))
								{
									goto endofstate;
								}
								SC_MustGetStringName (",");
							}
						}
						SC_MustGetStringName(")");
					}
					else 
					{
						SC_MustGetString();
						if (SC_Compare("("))
						{
							SC_ScriptError("You cannot pass parameters to '%s'\n",sc_String);
						}
						SC_UnGet();
					}
					goto endofstate;
				}
				SC_ScriptError("Invalid state parameter %s\n", sc_String);
			}
			SC_UnGet();
endofstate:
			StateArray.Push(state);
			while (*statestrp)
			{
				int frame=((*statestrp++)&223)-'A';

				if (frame<0 || frame>28)
				{
					SC_ScriptError ("Frames must be A-Z, [, \\, or ]");
					frame=0;
				}

				state.Frame=(state.Frame&(SF_FULLBRIGHT|SF_BIGTIC))|frame;
				StateArray.Push(state);
				count++;
			}
			laststate=&StateArray[count];
			count++;
		}
	}
	if (count<=minrequiredstate)
	{
		SC_ScriptError("A_Jump offset out of range in %s", actor->Class->TypeName.GetChars());
	}
	SC_SetEscape(true);	// re-enable escape sequences
	return count;
}
FxExpression *ParseParameter(FScanner &sc, PClass *cls, char type, bool constant)
{
	FxExpression *x = NULL;
	int v;

	switch(type)
	{
	case 'S':
	case 's':		// Sound name
		sc.MustGetString();
		x = new FxConstant(FSoundID(sc.String), sc);
		break;

	case 'M':
	case 'm':		// Actor name
		sc.SetEscape(true);
		sc.MustGetString();
		sc.SetEscape(false);
		x = new FxClassTypeCast(RUNTIME_CLASS(AActor), new FxConstant(FName(sc.String), sc));
		break;

	case 'T':
	case 't':		// String
		sc.SetEscape(true);
		sc.MustGetString();
		sc.SetEscape(false);
		x = new FxConstant(sc.String[0]? FName(sc.String) : NAME_None, sc);
		break;

	case 'C':
	case 'c':		// Color
		sc.MustGetString ();
		if (sc.Compare("none"))
		{
			v = -1;
		}
		else if (sc.Compare(""))
		{
			v = 0;
		}
		else
		{
			int c = V_GetColor (NULL, sc.String);
			// 0 needs to be the default so we have to mark the color.
			v = MAKEARGB(1, RPART(c), GPART(c), BPART(c));
		}
		{
			ExpVal val;
			val.Type = VAL_Color;
			val.Int = v;
			x = new FxConstant(val, sc);
			break;
		}

	case 'L':
	case 'l':
	{
		// This forces quotation marks around the state name.
		sc.MustGetToken(TK_StringConst);
		if (sc.String[0] == 0 || sc.Compare("None"))
		{
			x = new FxConstant((FState*)NULL, sc);
		}
		else if (sc.Compare("*"))
		{
			if (constant) 
			{
				x = new FxConstant((FState*)(intptr_t)-1, sc);
			}
			else sc.ScriptError("Invalid state name '*'");
		}
		else
		{
			x = new FxMultiNameState(sc.String, sc);
		}
		break;
	}

	case 'X':
	case 'x':
	case 'Y':
	case 'y':
		x = ParseExpression (sc, cls);
		if (constant && !x->isConstant())
		{
			sc.ScriptMessage("Default parameter must be constant.");
			FScriptPosition::ErrorCounter++;
		}
		break;

	default:
		assert(false);
		return NULL;
	}
	return x;
}