Example #1
0
	void ParseLinedef(line_t *ld, int index)
	{
		bool passuse = false;
		bool strifetrans = false;
		bool strifetrans2 = false;
		FString arg0str, arg1str;
		int lineid;	// forZDoomTranslated namespace
		FString tagstring;

		memset(ld, 0, sizeof(*ld));
		ld->Alpha = FRACUNIT;
		ld->sidedef[0] = ld->sidedef[1] = NULL;
		if (level.flags2 & LEVEL2_CLIPMIDTEX) ld->flags |= ML_CLIP_MIDTEX;
		if (level.flags2 & LEVEL2_WRAPMIDTEX) ld->flags |= ML_WRAP_MIDTEX;
		if (level.flags2 & LEVEL2_CHECKSWITCHRANGE) ld->flags |= ML_CHECKSWITCHRANGE;

		sc.MustGetToken('{');
		while (!sc.CheckToken('}'))
		{
			FName key = ParseKey();

			// This switch contains all keys of the UDMF base spec
			switch(key)
			{
			case NAME_V1:
				ld->v1 = (vertex_t*)(intptr_t)CheckInt(key);	// must be relocated later
				continue;

			case NAME_V2:
				ld->v2 = (vertex_t*)(intptr_t)CheckInt(key);	// must be relocated later
				continue;

			case NAME_Special:
				ld->special = CheckInt(key);
				if (namespc == NAME_Hexen)
				{
					if (ld->special < 0 || ld->special > 140 || !HexenLineSpecialOk[ld->special])
						ld->special = 0;	// NULL all specials which don't exist in Hexen
				}

				continue;

			case NAME_Id:
				lineid = CheckInt(key);
				tagManager.AddLineID(index, lineid);
				continue;

			case NAME_Sidefront:
				ld->sidedef[0] = (side_t*)(intptr_t)(1 + CheckInt(key));
				continue;

			case NAME_Sideback:
				ld->sidedef[1] = (side_t*)(intptr_t)(1 + CheckInt(key));
				continue;

			case NAME_Arg0:
			case NAME_Arg1:
			case NAME_Arg2:
			case NAME_Arg3:
			case NAME_Arg4:
				ld->args[int(key)-int(NAME_Arg0)] = CheckInt(key);
				continue;

			case NAME_Arg0Str:
				CHECK_N(Zd);
				arg0str = CheckString(key);
				continue;

			case NAME_Arg1Str:
				CHECK_N(Zd);
				arg1str = CheckString(key);
				continue;

			case NAME_Blocking:
				Flag(ld->flags, ML_BLOCKING, key); 
				continue;

			case NAME_Blockmonsters:
				Flag(ld->flags, ML_BLOCKMONSTERS, key); 
				continue;

			case NAME_Twosided:
				Flag(ld->flags, ML_TWOSIDED, key); 
				continue;

			case NAME_Dontpegtop:
				Flag(ld->flags, ML_DONTPEGTOP, key); 
				continue;

			case NAME_Dontpegbottom:
				Flag(ld->flags, ML_DONTPEGBOTTOM, key); 
				continue;

			case NAME_Secret:
				Flag(ld->flags, ML_SECRET, key); 
				continue;

			case NAME_Blocksound:
				Flag(ld->flags, ML_SOUNDBLOCK, key); 
				continue;

			case NAME_Dontdraw:
				Flag(ld->flags, ML_DONTDRAW, key); 
				continue;

			case NAME_Mapped:
				Flag(ld->flags, ML_MAPPED, key); 
				continue;

			case NAME_Jumpover:
				CHECK_N(St | Zd | Zdt | Va)
				Flag(ld->flags, ML_RAILING, key); 
				continue;

			case NAME_Blockfloaters:
				CHECK_N(St | Zd | Zdt | Va)
				Flag(ld->flags, ML_BLOCK_FLOATERS, key); 
				continue;

			case NAME_Translucent:
				CHECK_N(St | Zd | Zdt | Va)
				strifetrans = CheckBool(key); 
				continue;

			case NAME_Transparent:
				CHECK_N(St | Zd | Zdt | Va)
				strifetrans2 = CheckBool(key); 
				continue;

			case NAME_Passuse:
				CHECK_N(Dm | Zd | Zdt | Va)
				passuse = CheckBool(key); 
				continue;

			default:
				break;
			}

			// This switch contains all keys of the UDMF base spec which only apply to Hexen format specials
			if (!isTranslated) switch (key)
			{
			case NAME_Playercross:
				Flag(ld->activation, SPAC_Cross, key); 
				continue;

			case NAME_Playeruse:
				Flag(ld->activation, SPAC_Use, key); 
				continue;

			case NAME_Playeruseback:
				Flag(ld->activation, SPAC_UseBack, key); 
				continue;

			case NAME_Monstercross:
				Flag(ld->activation, SPAC_MCross, key); 
				continue;

			case NAME_Impact:
				Flag(ld->activation, SPAC_Impact, key); 
				continue;

			case NAME_Playerpush:
				Flag(ld->activation, SPAC_Push, key); 
				continue;

			case NAME_Missilecross:
				Flag(ld->activation, SPAC_PCross, key); 
				continue;

			case NAME_Monsteruse:
				Flag(ld->activation, SPAC_MUse, key); 
				continue;

			case NAME_Monsterpush:
				Flag(ld->activation, SPAC_MPush, key); 
				continue;

			case NAME_Repeatspecial:
				Flag(ld->flags, ML_REPEAT_SPECIAL, key); 
				continue;

			default:
				break;
			}

			// This switch contains all keys which are ZDoom specific
			if (namespace_bits & (Zd|Zdt|Va)) switch(key)
			{
			case NAME_Alpha:
				ld->Alpha = CheckFixed(key);
				continue;

			case NAME_Renderstyle:
			{
				const char *str = CheckString(key);
				if (!stricmp(str, "translucent")) ld->flags &= ~ML_ADDTRANS;
				else if (!stricmp(str, "add")) ld->flags |= ML_ADDTRANS;
				else sc.ScriptMessage("Unknown value \"%s\" for 'renderstyle'\n", str);
				continue;
			}

			case NAME_Anycross:
				Flag(ld->activation, SPAC_AnyCross, key); 
				continue;

			case NAME_Monsteractivate:
				Flag(ld->flags, ML_MONSTERSCANACTIVATE, key); 
				continue;

			case NAME_Blockplayers:
				Flag(ld->flags, ML_BLOCK_PLAYERS, key); 
				continue;

			case NAME_Blockeverything:
				Flag(ld->flags, ML_BLOCKEVERYTHING, key); 
				continue;

			case NAME_Zoneboundary:
				Flag(ld->flags, ML_ZONEBOUNDARY, key); 
				continue;

			case NAME_Clipmidtex:
				Flag(ld->flags, ML_CLIP_MIDTEX, key); 
				continue;

			case NAME_Wrapmidtex:
				Flag(ld->flags, ML_WRAP_MIDTEX, key); 
				continue;

			case NAME_Midtex3d:
				Flag(ld->flags, ML_3DMIDTEX, key); 
				continue;

			case NAME_Checkswitchrange:
				Flag(ld->flags, ML_CHECKSWITCHRANGE, key); 
				continue;

			case NAME_Firstsideonly:
				Flag(ld->flags, ML_FIRSTSIDEONLY, key); 
				continue;

			case NAME_blockprojectiles:
				Flag(ld->flags, ML_BLOCKPROJECTILE, key); 
				continue;

			case NAME_blockuse:
				Flag(ld->flags, ML_BLOCKUSE, key); 
				continue;

			case NAME_blocksight:
				Flag(ld->flags, ML_BLOCKSIGHT, key); 
				continue;
			
			case NAME_blockhitscan:
				Flag(ld->flags, ML_BLOCKHITSCAN, key); 
				continue;
			
			// [TP] Locks the special with a key
			case NAME_Locknumber:
				ld->locknumber = CheckInt(key);
				continue;

			// [TP] Causes a 3d midtex to behave like an impassible line
			case NAME_Midtex3dimpassible:
				Flag(ld->flags, ML_3DMIDTEX_IMPASS, key);
				continue;

			case NAME_MoreIds:
				// delay parsing of the tag string until parsing of the sector is complete
				// This ensures that the ID is always the first tag in the list.
				tagstring = CheckString(key);
				break;


			default:
				break;
			}


			if ((namespace_bits & (Zd | Zdt)) && !strnicmp("user_", key.GetChars(), 5))
			{
				AddUserKey(key, UDMF_Line, index);
			}
		}

		if (tagstring.IsNotEmpty())
		{
			FScanner sc;
			sc.OpenString("tagstring", tagstring);
			// scan the string as long as valid numbers can be found
			while (sc.CheckNumber())
			{
				if (sc.Number != 0)	tagManager.AddLineID(index, sc.Number);
			}
		}

		if (isTranslated)
		{
			int saved = ld->flags;

			maplinedef_t mld;
			memset(&mld, 0, sizeof(mld));
			mld.special = ld->special;
			mld.tag = lineid;
			P_TranslateLineDef(ld, &mld);
			ld->flags = saved | (ld->flags&(ML_MONSTERSCANACTIVATE|ML_REPEAT_SPECIAL|ML_FIRSTSIDEONLY));
		}
		if (passuse && (ld->activation & SPAC_Use)) 
		{
			ld->activation = (ld->activation & ~SPAC_Use) | SPAC_UseThrough;
		}
		if (strifetrans && ld->Alpha == FRACUNIT)
		{
			ld->Alpha = FRACUNIT * 3/4;
		}
		if (strifetrans2 && ld->Alpha == FRACUNIT)
		{
			ld->Alpha = FRACUNIT * 1/4;
		}
		if (ld->sidedef[0] == NULL)
		{
			ld->sidedef[0] = (side_t*)(intptr_t)(1);
			Printf("Line %d has no first side.\n", index);
		}
		if (arg0str.IsNotEmpty() && (P_IsACSSpecial(ld->special) || ld->special == 0))
		{
			ld->args[0] = -FName(arg0str);
		}
		if (arg1str.IsNotEmpty() && (P_IsThingSpecial(ld->special) || ld->special == 0))
		{
			ld->args[1] = -FName(arg1str);
		}
		if ((ld->flags & ML_3DMIDTEX_IMPASS) && !(ld->flags & ML_3DMIDTEX)) // [TP]
		{
			Printf ("Line %d has midtex3dimpassible without midtex3d.\n", index);
		}
	}
Example #2
0
	void ParseSector(sector_t *sec, int index)
	{
		int lightcolor = -1;
		int fadecolor = -1;
		int desaturation = -1;
		int fplaneflags = 0, cplaneflags = 0;
		double fp[4] = { 0 }, cp[4] = { 0 };
		FString tagstring;

		memset(sec, 0, sizeof(*sec));
		sec->lightlevel = 160;
		sec->SetXScale(sector_t::floor, FRACUNIT);	// [RH] floor and ceiling scaling
		sec->SetYScale(sector_t::floor, FRACUNIT);
		sec->SetXScale(sector_t::ceiling, FRACUNIT);
		sec->SetYScale(sector_t::ceiling, FRACUNIT);
		sec->SetAlpha(sector_t::floor, FRACUNIT);
		sec->SetAlpha(sector_t::ceiling, FRACUNIT);
		sec->thinglist = NULL;
		sec->touching_thinglist = NULL;		// phares 3/14/98
		sec->seqType = (level.flags & LEVEL_SNDSEQTOTALCTRL) ? 0 : -1;
		sec->nextsec = -1;	//jff 2/26/98 add fields to support locking out
		sec->prevsec = -1;	// stair retriggering until build completes
		sec->heightsec = NULL;	// sector used to get floor and ceiling height
		sec->sectornum = index;
		if (floordrop) sec->Flags = SECF_FLOORDROP;
		// killough 3/7/98: end changes

		sec->gravity = 1.f;	// [RH] Default sector gravity of 1.0
		sec->ZoneNumber = 0xFFFF;

		// killough 8/28/98: initialize all sectors to normal friction
		sec->friction = ORIG_FRICTION;
		sec->movefactor = ORIG_FRICTION_FACTOR;

		sc.MustGetToken('{');
		while (!sc.CheckToken('}'))
		{
			FName key = ParseKey();
			switch(key)
			{
			case NAME_Heightfloor:
				sec->SetPlaneTexZ(sector_t::floor, CheckInt(key) << FRACBITS);
				continue;

			case NAME_Heightceiling:
				sec->SetPlaneTexZ(sector_t::ceiling, CheckInt(key) << FRACBITS);
				continue;

			case NAME_Texturefloor:
				SetTexture(sec, index, sector_t::floor, CheckString(key), missingTex, false);
				continue;

			case NAME_Textureceiling:
				SetTexture(sec, index, sector_t::ceiling, CheckString(key), missingTex, false);
				continue;

			case NAME_Lightlevel:
				sec->lightlevel = sector_t::ClampLight(CheckInt(key));
				continue;

			case NAME_Special:
				sec->special = (short)CheckInt(key);
				if (isTranslated) sec->special = P_TranslateSectorSpecial(sec->special);
				else if (namespc == NAME_Hexen)
				{
					if (sec->special < 0 || sec->special > 255 || !HexenSectorSpecialOk[sec->special])
						sec->special = 0;	// NULL all unknown specials
				}
				continue;

			case NAME_Id:
				tagManager.AddSectorTag(index, CheckInt(key));
				continue;

			default:
				break;
			}

			if (namespace_bits & (Zd|Zdt|Va)) switch(key)
			{
				case NAME_Xpanningfloor:
					sec->SetXOffset(sector_t::floor, CheckFixed(key));
					continue;

				case NAME_Ypanningfloor:
					sec->SetYOffset(sector_t::floor, CheckFixed(key));
					continue;

				case NAME_Xpanningceiling:
					sec->SetXOffset(sector_t::ceiling, CheckFixed(key));
					continue;

				case NAME_Ypanningceiling:
					sec->SetYOffset(sector_t::ceiling, CheckFixed(key));
					continue;

				case NAME_Xscalefloor:
					sec->SetXScale(sector_t::floor, CheckFixed(key));
					continue;

				case NAME_Yscalefloor:
					sec->SetYScale(sector_t::floor, CheckFixed(key));
					continue;

				case NAME_Xscaleceiling:
					sec->SetXScale(sector_t::ceiling, CheckFixed(key));
					continue;

				case NAME_Yscaleceiling:
					sec->SetYScale(sector_t::ceiling, CheckFixed(key));
					continue;

				case NAME_Rotationfloor:
					sec->SetAngle(sector_t::floor, CheckAngle(key));
					continue;

				case NAME_Rotationceiling:
					sec->SetAngle(sector_t::ceiling, CheckAngle(key));
					continue;

				case NAME_Lightfloor:
					sec->SetPlaneLight(sector_t::floor, CheckInt(key));
					continue;

				case NAME_Lightceiling:
					sec->SetPlaneLight(sector_t::ceiling, CheckInt(key));
					continue;

				case NAME_Alphafloor:
					sec->SetAlpha(sector_t::floor, CheckFixed(key));
					continue;

				case NAME_Alphaceiling:
					sec->SetAlpha(sector_t::ceiling, CheckFixed(key));
					continue;

				case NAME_Renderstylefloor:
				{
					const char *str = CheckString(key);
					if (!stricmp(str, "translucent")) sec->ChangeFlags(sector_t::floor, PLANEF_ADDITIVE, 0);
					else if (!stricmp(str, "add")) sec->ChangeFlags(sector_t::floor, 0, PLANEF_ADDITIVE);
					else sc.ScriptMessage("Unknown value \"%s\" for 'renderstylefloor'\n", str);
					continue;
				}

				case NAME_Renderstyleceiling:
				{
					const char *str = CheckString(key);
					if (!stricmp(str, "translucent")) sec->ChangeFlags(sector_t::ceiling, PLANEF_ADDITIVE, 0);
					else if (!stricmp(str, "add")) sec->ChangeFlags(sector_t::ceiling, 0, PLANEF_ADDITIVE);
					else sc.ScriptMessage("Unknown value \"%s\" for 'renderstyleceiling'\n", str);
					continue;
				}

				case NAME_Lightfloorabsolute:
					if (CheckBool(key)) sec->ChangeFlags(sector_t::floor, 0, PLANEF_ABSLIGHTING);
					else sec->ChangeFlags(sector_t::floor, PLANEF_ABSLIGHTING, 0);
					continue;

				case NAME_Lightceilingabsolute:
					if (CheckBool(key)) sec->ChangeFlags(sector_t::ceiling, 0, PLANEF_ABSLIGHTING);
					else sec->ChangeFlags(sector_t::ceiling, PLANEF_ABSLIGHTING, 0);
					continue;

				case NAME_Gravity:
					sec->gravity = float(CheckFloat(key));
					continue;

				case NAME_Lightcolor:
					lightcolor = CheckInt(key);
					continue;

				case NAME_Fadecolor:
					fadecolor = CheckInt(key);
					continue;

				case NAME_Desaturation:
					desaturation = int(255*CheckFloat(key));
					continue;

				case NAME_Silent:
					Flag(sec->Flags, SECF_SILENT, key);
					continue;

				case NAME_NoRespawn:
					Flag(sec->Flags, SECF_NORESPAWN, key);
					continue;

				case NAME_Nofallingdamage:
					Flag(sec->Flags, SECF_NOFALLINGDAMAGE, key);
					continue;

				case NAME_Dropactors:
					Flag(sec->Flags, SECF_FLOORDROP, key);
					continue;

				case NAME_SoundSequence:
					sec->SeqName = CheckString(key);
					sec->seqType = -1;
					continue;

				case NAME_hidden:
					Flag(sec->MoreFlags, SECF_HIDDEN, key);
					break;

				case NAME_Waterzone:
					Flag(sec->MoreFlags, SECF_UNDERWATER, key);
					break;

				case NAME_floorplane_a:
					fplaneflags |= 1;
					fp[0] = CheckFloat(key);
					break;

				case NAME_floorplane_b:
					fplaneflags |= 2;
					fp[1] = CheckFloat(key);
					break;

				case NAME_floorplane_c:
					fplaneflags |= 4;
					fp[2] = CheckFloat(key);
					break;

				case NAME_floorplane_d:
					fplaneflags |= 8;
					fp[3] = CheckFloat(key);
					break;

				case NAME_ceilingplane_a:
					cplaneflags |= 1;
					cp[0] = CheckFloat(key);
					break;

				case NAME_ceilingplane_b:
					cplaneflags |= 2;
					cp[1] = CheckFloat(key);
					break;

				case NAME_ceilingplane_c:
					cplaneflags |= 4;
					cp[2] = CheckFloat(key);
					break;

				case NAME_ceilingplane_d:
					cplaneflags |= 8;
					cp[3] = CheckFloat(key);
					break;

				case NAME_MoreIds:
					// delay parsing of the tag string until parsing of the sector is complete
					// This ensures that the ID is always the first tag in the list.
					tagstring = CheckString(key);
					break;

				default:
					break;
			}
			if ((namespace_bits & (Zd | Zdt)) && !strnicmp("user_", key.GetChars(), 5))
			{
				AddUserKey(key, UDMF_Sector, index);
			}
		}

		if (tagstring.IsNotEmpty())
		{
			FScanner sc;
			sc.OpenString("tagstring", tagstring);
			// scan the string as long as valid numbers can be found
			while (sc.CheckNumber())
			{
				if (sc.Number != 0)	tagManager.AddSectorTag(index, sc.Number);
			}
		}

		sec->secretsector = !!(sec->special&SECRET_MASK);
		
		// Reset the planes to their defaults if not all of the plane equation's parameters were found.
		if (fplaneflags != 15)
		{
			sec->floorplane.a = sec->floorplane.b = 0;
			sec->floorplane.d = -sec->GetPlaneTexZ(sector_t::floor);
			sec->floorplane.c = FRACUNIT;
			sec->floorplane.ic = FRACUNIT;
		}
		else
		{
			double ulen = TVector3<double>(fp[0], fp[1], fp[2]).Length();

			// normalize the vector, it must have a length of 1
			sec->floorplane.a = FLOAT2FIXED(fp[0] / ulen);
			sec->floorplane.b = FLOAT2FIXED(fp[1] / ulen);
			sec->floorplane.c = FLOAT2FIXED(fp[2] / ulen);
			sec->floorplane.d = FLOAT2FIXED(fp[3] / ulen);
			sec->floorplane.ic = FLOAT2FIXED(ulen / fp[2]);
		}
		if (cplaneflags != 15)
		{
			sec->ceilingplane.a = sec->ceilingplane.b = 0;
			sec->ceilingplane.d = sec->GetPlaneTexZ(sector_t::ceiling);
			sec->ceilingplane.c = -FRACUNIT;
			sec->ceilingplane.ic = -FRACUNIT;
		}
		else
		{
			double ulen = TVector3<double>(cp[0], cp[1], cp[2]).Length();

			// normalize the vector, it must have a length of 1
			sec->ceilingplane.a = FLOAT2FIXED(cp[0] / ulen);
			sec->ceilingplane.b = FLOAT2FIXED(cp[1] / ulen);
			sec->ceilingplane.c = FLOAT2FIXED(cp[2] / ulen);
			sec->ceilingplane.d = FLOAT2FIXED(cp[3] / ulen);
			sec->ceilingplane.ic = FLOAT2FIXED(ulen / cp[2]);
		}

		if (lightcolor == -1 && fadecolor == -1 && desaturation == -1)
		{
			// [RH] Sectors default to white light with the default fade.
			//		If they are outside (have a sky ceiling), they use the outside fog.
			if (level.outsidefog != 0xff000000 && (sec->GetTexture(sector_t::ceiling) == skyflatnum || (sec->special&0xff) == Sector_Outside))
			{
				if (fogMap == NULL)
					fogMap = GetSpecialLights (PalEntry (255,255,255), level.outsidefog, 0);
				sec->ColorMap = fogMap;
			}
			else
			{
				if (normMap == NULL)
					normMap = GetSpecialLights (PalEntry (255,255,255), level.fadeto, NormalLight.Desaturate);
				sec->ColorMap = normMap;
			}
		}
		else
		{
			if (lightcolor == -1) lightcolor = PalEntry(255,255,255);
			if (fadecolor == -1) 
			{
				if (level.outsidefog != 0xff000000 && (sec->GetTexture(sector_t::ceiling) == skyflatnum || (sec->special&0xff) == Sector_Outside))
					fadecolor = level.outsidefog;
				else
					fadecolor = level.fadeto;
			}
			if (desaturation == -1) desaturation = NormalLight.Desaturate;

			sec->ColorMap = GetSpecialLights (lightcolor, fadecolor, desaturation);
		}
	}