PWAD   ÜD  version "3.7.2"

// This will place lights on textures
// Meant for vanilla maps
// 3D floors are not supported (not until Graf pulls my goddamn PR)
// Some other things aren't done yet
// There will be misalignments because I haven't bothered with handling
// pegged/unpegged flags properly yet
// The lights are static
// Stuff like making them follow scrollers or change brightness
// based on light level, or handle animations...
// All of that is left as an exercise to whoever picks this up
// because I can't be arsed to do it
// I'm abandoning this mess in its current sorry state
// Fuck all of this noise, I have better things to do than waste my time on
// this tedious nonsense
//
// I am not doing your homework
//   -- Marisa

Class TextureHotspot
{
	int xpos, ypos, r, g, b, radius, spotin, spotout;
	bool isspot;
}

Class LightTexture
{
	TextureID tex;
	Vector2 size;
	Array<TextureHotspot> hotspots;
}

Class LightTextureHandler : EventHandler
{
	Array<LightTexture> ltex;

	override void OnRegister()
	{
		ltex.Clear();
		int lmp;
		if ( (lmp = Wads.FindLump("LTEXDEFS")) == -1 ) return;
		String txt = Wads.ReadLump(lmp);
		Array<String> lines, cline;
		lines.Clear();
		txt.Split(lines,"\n",0);
		int nspots = 0;
		LightTexture ltx;
		TextureHotspot hs;
		for ( int i=0; i<lines.size(); i++ )
		{
			if ( (lines[i].CharAt(0) == "#")
				|| (lines[i].Length() <= 1) ) continue;
			cline.Clear();
			lines[i].Split(cline," ",0);
			if ( nspots )
			{
				if ( (cline.size() != 6) && (cline.size() != 8) )
				{
					Console.Printf("LTEXDEFS: line %d: expected 6 or 8 tokens, got %d.",i+1,cline.size());
					return;
				}
				hs = new("TextureHotspot");
				hs.xpos = cline[0].ToInt();
				hs.ypos = cline[1].ToInt();
				hs.r = cline[2].ToInt();
				hs.g = cline[3].ToInt();
				hs.b = cline[4].ToInt();
				hs.radius = cline[5].ToInt();
				if ( cline.size() == 8 )
				{
					hs.spotin = cline[6].ToInt();
					hs.spotout = cline[7].ToInt();
					hs.isspot = true;
				}
				else hs.isspot = false;
				ltx.hotspots.Push(hs);
				nspots--;
				continue;
			}
			if ( (cline.size() != 2) && (cline.size() != 3) )
			{
				Console.Printf("LTEXDEFS: line %d: expected 2 or 3 tokens, got %d.",i+1,cline.size());
				return;
			}
			ltx = new("LightTexture");
			if ( cline.size() == 2 )
			{
				ltx.tex = TexMan.CheckForTexture(cline[0],TexMan.Type_Any);
				nspots = cline[1].ToInt();
			}
			else
			{
				if ( cline[1] ~== "T" ) ltx.tex = TexMan.CheckForTexture(cline[0],TexMan.Type_Wall);
				else if ( cline[1] ~== "F" ) ltx.tex = TexMan.CheckForTexture(cline[0],TexMan.Type_Flat);
				else ltx.tex = TexMan.CheckForTexture(cline[0],TexMan.Type_Any);
				nspots = cline[2].ToInt();
			}
			ltx.size = TexMan.GetScaledSize(ltx.tex);
			ltx.hotspots.Clear();
			ltex.Push(ltx);
		}
		if ( nspots ) Console.Printf("LTEXDEFS: reached EOF when %d more hotspot definitions were expected",nspots);
	}

	void PopulateSideSection( Side s, int part, int h, Vector3 pos, Vector2 dir, Vector2 normal )
	{
		// check texture first
		let t = s.GetTexture(part);
		if ( !t.IsValid() || t.IsNull() ) return;
		int ltx = -1;
		for ( int i=0; i<ltex.Size(); i++ )
		{
			if ( ltex[i].tex != t ) continue;
			ltx = i;
			break;
		}
		if ( ltx == -1 ) return;
		int w = int((s.v2().p-s.v1().p).length());
		double xo, yo, xs, ys;
		int tw, th;
		xo = s.GetTextureXOffset(part);
		yo = s.GetTextureYOffset(part);
		xs = s.GetTextureXScale(part);
		ys = s.GetTextureYScale(part);
		// TODO properly handle pegged/unpegged flags
		// also TODO fix misalignment on upper textures
		tw = int(ltex[ltx].size.x);
		th = int(ltex[ltx].size.y);
		for ( int y=0; y<h; y++ ) for ( int x=0; x<w; x++ )
		{
			int ox = int((x+xo)*xs);
			int oy = int((y+yo)*ys);
			for ( int i=0; i<ltex[ltx].hotspots.Size(); i++ )
			{
				if ( (ox%tw == ltex[ltx].hotspots[i].xpos) && (oy%th == ltex[ltx].hotspots[i].ypos) )
				{
					if ( !level.IsPointInLevel(pos+(x*dir.x,x*dir.y,-y)+(normal.x*8.,normal.y*8.,0)) ) continue;
					let l = Actor.Spawn("PointLightAttenuated",pos+(x*dir.x,x*dir.y,-y)+(normal.x*8.,normal.y*8.,0));
					l.args[0] = ltex[ltx].hotspots[i].r;
					l.args[1] = ltex[ltx].hotspots[i].g;
					l.args[2] = ltex[ltx].hotspots[i].b;
					l.args[3] = ltex[ltx].hotspots[i].radius;
				}
			}
		}
	}

	void PopulateSectorPlane( Sector s, int part, Secplane plane )
	{
		// check texture first
		let t = s.GetTexture(part);
		if ( !t.IsValid() || t.IsNull() ) return;
		int ltx = -1;
		for ( int i=0; i<ltex.Size(); i++ )
		{
			if ( ltex[i].tex != t ) continue;
			ltx = i;
			break;
		}
		if ( ltx == -1 ) return;
		int sx = int.max, sy = int.max, ex = int.min, ey = int.min;
		// calc bounds
		for ( int i=0; i<s.lines.Size(); i++ )
		{
			if ( s.lines[i].v1.p.x < sx ) sx = int(s.lines[i].v1.p.x);
			if ( s.lines[i].v2.p.x < sx ) sx = int(s.lines[i].v2.p.x);
			if ( s.lines[i].v1.p.x > ex ) ex = int(s.lines[i].v1.p.x);
			if ( s.lines[i].v2.p.x > ex ) ex = int(s.lines[i].v2.p.x);
			if ( s.lines[i].v1.p.y < sy ) sy = int(s.lines[i].v1.p.y);
			if ( s.lines[i].v2.p.y < sy ) sy = int(s.lines[i].v2.p.y);
			if ( s.lines[i].v1.p.y > ey ) ey = int(s.lines[i].v1.p.y);
			if ( s.lines[i].v2.p.y > ey ) ey = int(s.lines[i].v2.p.y);
		}
		double xo, yo, xs, ys, ang;
		int tw, th;
		xo = s.GetXOffset(part);
		yo = s.GetYOffset(part);
		xs = s.GetXScale(part);
		ys = s.GetYScale(part);
		ang = s.GetAngle(part);	// TODO handle rotation
		tw = int(ltex[ltx].size.x);
		th = int(ltex[ltx].size.y);
		for ( int y=sy; y<ey; y++ ) for ( int x=sx; x<ex; x++ )
		{
			if ( level.PointInSector((x,y)) != s ) continue;
			int ox = int((x+xo)*xs);
			int oy = int((y+yo)*ys);
			if ( ox < 0 ) ox = tw-ox;
			if ( oy < 0 ) oy = th-oy;
			for ( int i=0; i<ltex[ltx].hotspots.Size(); i++ )
			{
				if ( (ox%tw == ltex[ltx].hotspots[i].xpos) && (oy%th == ltex[ltx].hotspots[i].ypos) )
				{
					if ( !level.IsPointInLevel((x,y,plane.ZAtPoint((x,y)))+plane.Normal*8.) ) continue;
					Actor l;
					if ( ltex[ltx].hotspots[i].isspot )
					{
						l = Actor.Spawn("SpotLightAttenuated",(x,y,plane.ZAtPoint((x,y)))+plane.Normal*8.);
						DynamicLight(l).SpotInnerAngle = ltex[ltx].hotspots[i].spotin;
						DynamicLight(l).SpotOuterAngle = ltex[ltx].hotspots[i].spotout;
						l.angle = atan2(plane.Normal.y,plane.Normal.x);
						l.pitch = asin(-plane.Normal.z);
					}
					else l = Actor.Spawn("PointLightAttenuated",(x,y,plane.ZAtPoint((x,y)))+plane.Normal*8.);
					l.args[0] = ltex[ltx].hotspots[i].r;
					l.args[1] = ltex[ltx].hotspots[i].g;
					l.args[2] = ltex[ltx].hotspots[i].b;
					l.args[3] = ltex[ltx].hotspots[i].radius;
				}
			}
		}
	}

	override void WorldLoaded( WorldEvent e )
	{
		if ( e.IsSaveGame || e.IsReopen ) return;
		for ( int i=0; i<level.Lines.Size(); i++ )
		{
			Line l = level.Lines[i];
			Vector2 n = (l.delta.y,-l.delta.x).unit();
			Vector3 p1, p2;
			p1.xy = l.v1.p;
			p2.xy = l.v2.p;
			if ( l.sidedef[1] )
			{
				// this part is a mess
				int c1, f1, c2, f2;
				c1 = int(l.frontsector.ceilingplane.ZAtPoint(l.v1.p));
				f1 = int(l.frontsector.floorplane.ZAtPoint(l.v1.p));
				c2 = int(l.backsector.ceilingplane.ZAtPoint(l.v1.p));
				f2 = int(l.backsector.floorplane.ZAtPoint(l.v1.p));
				// front upper
				p1.z = c1;
				if ( c1-c2 > 0 ) PopulateSideSection(l.sidedef[0],0,c1-c2,p1,l.delta.unit(),n);
				// front middle
				p1.z = c2;
				if ( c2-f2 > 0 ) PopulateSideSection(l.sidedef[0],1,c2-f2,p1,l.delta.unit(),n);
				// front bottom
				p1.z = f2;
				if ( f2-f1 > 0 ) PopulateSideSection(l.sidedef[0],2,f2-f1,p1,l.delta.unit(),n);
				// back upper
				p2.z = c2;
				if ( c2-c1 > 0 ) PopulateSideSection(l.sidedef[1],0,c2-c1,p2,-l.delta.unit(),-n);
				// back middle
				p2.z = c2;
				if ( c1-f1 > 0 ) PopulateSideSection(l.sidedef[1],1,c1-f1,p2,-l.delta.unit(),-n);
				// back bottom
				p2.z = f1;
				if ( f1-f2 > 0 ) PopulateSideSection(l.sidedef[1],2,f1-f2,p2,-l.delta.unit(),-n);
			}
			else
			{
				int c, f;
				c = int(l.frontsector.ceilingplane.ZAtPoint(l.v1.p));
				f = int(l.frontsector.floorplane.ZAtPoint(l.v1.p));
				p1.z = c;
				PopulateSideSection(l.sidedef[0],1,c-f,p1,l.delta.unit(),n);
			}
		}
		for ( int i=0; i<level.Sectors.Size(); i++ )
		{
			Sector s = level.Sectors[i];
			PopulateSectorPlane(s,0,s.floorplane);
			PopulateSectorPlane(s,1,s.ceilingplane);
		}
	}
}
GameInfo
{
	AddEventHandlers = "LightTextureHandler"
}
# This is the most inefficient thing I've ever come up with
# How it works:
# Each texture definition starts with the name and a number of light "hotspots"
# An optional extra parameter can be used to specify a type in case there's
# some conflicting name dickery (e.g. a flat and a wall texture with same name)
# in which case you'd add T or F after the name
# Each hotspot can have either 6 or 8 parameters
# The parameters are x and y positions in the texture, then a rgb color, and
# a radius. If the other two parameters are given, then this hotspot is
# turned into a spotlight, and they become the inner/outer angles
# Spotlights are automatically oriented to face away from the surface
#
# All the stuff in e1m1 is covered here, I won't even fucking bother with doing
# the rest, fuck that noise
#

A-BROWN4 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



A-pois 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



A-yellow 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



bigbrik3 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



bigdoor1 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



bigdoor2 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



bigdoor3 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



bigdoor4 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



bigdoor5 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



Bigdoor6 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



bigdoor7 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



bricklit 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



brnpois 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



brnpois2 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720


ceil1_2 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



ceil1_3 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



cement4 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



cement8 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



cempois 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



comp2 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



compsta1 2
1 16 2 7 157 20
1 16 2 7 157 200 240 720



compsta2 2
1 16 10 104 4 20
1 16 10 104 4 200 240 720



comptall 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



compute1 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



compute2 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



compute3 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720





cons1_1 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



cons1_5 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



cons1_7 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720







dem1_1 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



dem1_2 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



dem1_3 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



dem1_4 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



door1 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



DOOR2 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



DOOR2_4 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



door3 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



DOOR3_4 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



DOOR3_5 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



DOOR9_1 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



DOOR9_2 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



doorblu 2
1 16 0 105 254 20
1 16 0 105 254 200 240 720



doorblu2 2
1 16 0 105 254 20
1 16 0 105 254 200 240 720



doorhi 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



DOORMET1 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



doorred 2
1 16 151 1 0 20
1 16 151 1 0 200 240 720



doorred2 2
1 16 151 1 0 20
1 16 151 1 0 200 240 720



doorstop 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



doortrak 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



dooryel 2
1 16 255 160 64 20
1 16 128 80 32 200 30 90



dooryel2 2
1 16 255 160 64 20
1 16 128 80 32 200 30 90



Eggreeni 2
1 16 0 153 51 200
1 16 0 153 51 200 240 720



EGREDI 2
1 16 151 1 0 20
1 16 151 1 0 200 240 720





Exit1 2
1 16 151 1 0 20
1 16 151 1 0 200 240 720



Exitdoor 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



exitsign 2
1 16 151 1 0 20
1 16 151 1 0 200 240 720



exitston 2
1 16 151 1 0 20
1 16 151 1 0 200 240 720




flat2 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



flat22 2
1 16 0 105 254 20
1 16 0 105 254 200 240 720




gate1 2
1 16 151 1 0 20
1 16 151 1 0 200 240 720



gate2 2
1 16 151 1 0 20
1 16 151 1 0 200 240 720



gate3 2
1 16 151 1 0 20
1 16 151 1 0 200 240 720



gate4 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



graypois 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



gstfont1 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



gstfont2 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



gstfont3 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



gstgarg 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



gstlion 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



gstsatyr 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



ickdoor1 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



lite2 2
1 16 255 160 64 20
1 16 128 80 32 200 30 90



lite3 2
1 16 255 160 64 20
1 16 128 80 32 200 30 90



lite4 2
1 16 255 160 64 20
1 16 128 80 32 200 30 90



lite5 2
1 16 255 160 64 20
1 16 128 80 32 200 30 90



lite96 2
1 16 255 160 64 20
1 16 128 80 32 200 30 90



liteblu1 2
1 16 0 105 254 20
1 16 0 105 254 200 240 720



liteblu2 2
1 16 0 105 254 20
1 16 0 105 254 200 240 720



liteblu3 2
1 16 0 105 254 20
1 16 0 105 254 200 240 720



liteblu4 2
1 16 0 105 254 20
1 16 0 105 254 200 240 720



litegrn1 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



litemet 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



litered 2
1 16 151 1 0 20
1 16 151 1 0 200 240 720



litered1 2
1 16 151 1 0 20
1 16 151 1 0 200 240 720



Litered2 2
1 16 151 1 0 20
1 16 151 1 0 200 240 720



liteston 2
1 16 255 160 64 20
1 16 128 80 32 200 30 90



liteyel1 2
1 16 255 160 64 20
1 16 128 80 32 200 30 90



liteyel2 2
1 16 255 160 64 20
1 16 128 80 32 200 30 90



LITEYEL3 2
1 16 255 160 64 20
1 16 128 80 32 200 30 90



marbfac2 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



marbfac3 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



Marbfac4 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



marbface 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



metal3 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720






M_Tec 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



M_YDOOR 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



Nukepois 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



panblack 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



panblue 2
1 16 0 105 254 20
1 16 0 105 254 200 240 720



panred 2
1 16 151 1 0 20
1 16 151 1 0 200 240 720



pipewal1 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



planet1 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720




Pnk4exit 2
1 16 151 1 0 20
1 16 151 1 0 200 240 720



silver2 2
1 16 0 105 254 20
1 16 0 105 254 200 240 720





sladpois 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



Slime3 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



Slime8 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



spacew3 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



spcdoor1 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



spcdoor2 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



spcdoor3 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



spcdoor4 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



step04 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



Step08 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



Step09 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



Step5 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



Step8 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



Step9 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



stonpois 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720





T14_5 2
1 16 255 160 64 20
1 16 128 80 32 200 30 90



tekbron2 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



tekgren3 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



tekgren5 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



Tilite6_1 2
1 16 255 160 64 20
1 16 128 80 32 200 30 90



tlite6_1 2
1 16 255 160 64 20
1 16 128 80 32 200 30 90



tlite6_4 2
1 16 255 160 64 20
1 16 128 80 32 200 30 90



tlite6_5 2
1 16 151 1 0 20
1 16 151 1 0 200 240 720



tlite6_6 2
1 16 255 160 64 20
1 16 128 80 32 200 30 90



WALL03_1 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



wood4 2
1 16 151 1 0 20
1 16 151 1 0 200 240 720



woodgarg 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



woodmet2 2
1 16 90 76 59 200
1 16 90 76 59 200 240 720



woodskul 2
1 16 151 1 0 20
1 16 151 1 0 200 240 720




   ¡   ZSCRIPT ­   7   ZMAPINFOä   ø#  LTEXDEFS