{****************************************************************************
*                      The DOOM Hacker's Tool Kit                           *
*****************************************************************************
* Unit: 	  MAPS                                                             *
* Purpose: Loading and displaying the Maps from the WAD File                *
* Date:    4/28/94                                                          *
* Author:  Joshua Jackson        Internet: joshjackson@delphi.com           *
****************************************************************************}

{$O+,F+}
unit Maps;

interface

uses Wad,WadDecl,DOOMGUI,GUIObj;

type  PWadMapViewer=^TWadMapViewer;
		TWadMapViewer=TGraphGroup;
		PWadMap=^TWadMap;
		TWadMap=Object(TGraphView)
			LevelEntries:PLevelEntries;
			ThingList	:PThingList;
			VertexList	:PVertexList;
			LineDefList	:PLineDefList;
			ViewerMask	:word;
			ThingMask	:word;
			ScaleInc,XOffset,YOffset:word;
			Constructor Init(WDir:PWadDirectory;LevelName:ObjNameStr);
			Procedure Draw; virtual;
			Procedure SetScale(NewScaleInc,NewXOffset,NewYOffset:word);
			Function GetThingInArea(x1,y1,x2,y2:word):word;
			Destructor Done; virtual;
		end;

implementation

uses crt,graph;

Function OnSkillLevel(Attr,ViewerMask:word):boolean;

	var TempAttr:word;

	begin
		TempAttr:=(ViewerMask and 64);
		if (TempAttr=0) and ((Attr and 16) = 16) then begin
			OnSkillLevel:=False;
			exit;
		end;
		TempAttr:=(ViewerMask and 56) shr 3;
		if (TempAttr and (Attr and 7)) = TempAttr then
			OnSkillLevel:=True
		else
			OnSkillLevel:=False;
	end;

Constructor TWadMap.Init(WDir:PWadDirectory;LevelName:ObjNameStr);

	var	Entry,LevelPos:word;
			R:TGraphRect;

	begin
		Owner:=Nil;
		Next:=Nil;
		ScaleInc:=1;
		XOffset:=0;
		YOffset:=0;
		R.Assign(0,0,639,479);
		Bounds:=R;
		New(LevelEntries);
		LevelPos:=WDir^.FindObject(LevelName);
		if LevelPos=0 then begin
			writeln('TWapMap_Init: Invalid Level Name ',LevelName);
			halt;
		end;
		LevelEntries^.MapID:=WDir^.DirEntry^[LevelPos];
		LevelEntries^.Things:=WDir^.DirEntry^[LevelPos+1];
		LevelEntries^.LineDefs:=WDir^.DirEntry^[LevelPos+2];
		LevelEntries^.SideDefs:=WDir^.DirEntry^[LevelPos+3];
		LevelEntries^.Vertexes:=WDir^.DirEntry^[LevelPos+4];
		LevelEntries^.Segs:=WDir^.DirEntry^[LevelPos+5];
		LevelEntries^.SSectors:=WDir^.DirEntry^[LevelPos+6];
		LevelEntries^.Nodes:=WDir^.DirEntry^[LevelPos+7];
		LevelEntries^.Sectors:=WDir^.DirEntry^[LevelPos+8];
		LevelEntries^.Reject:=WDir^.DirEntry^[LevelPos+9];
		LevelEntries^.BlockMap:=WDir^.DirEntry^[LevelPos+10];
		GetMem(ThingList,LevelEntries^.Things.ObjLength);
		Seek(WDir^.WadFile,LevelEntries^.Things.ObjStart);
		BlockRead(WDir^.WadFile,ThingList^,LevelEntries^.Things.ObjLength);
		GetMem(VertexList,LevelEntries^.Vertexes.ObjLength);
		Seek(WDir^.WadFile,LevelEntries^.Vertexes.ObjStart);
		BlockRead(WDir^.WadFile,VertexList^,LevelEntries^.Vertexes.ObjLength);
		GetMem(LineDefList,LevelEntries^.LineDefs.ObjLength);
		Seek(WDir^.WadFile,LevelEntries^.LineDefs.ObjStart);
		BlockRead(WDir^.WadFile,LineDefList^,LevelEntries^.LineDefs.ObjLength);
	end;

Procedure TWadMap.Draw;

	var	MidX,MidY,MaxX,MaxY,MinX,MinY:integer;
			ScaleX,ScaleY,Scale:real;
			IntScale:Longint;
			x,y,NumThings,NumLines,gd,gm,t:integer;
			ch,SkillLevel:Char;
			TempStr:String;
			TT:word;
			SubView:PGraphView;

	begin
		MinX:=32000;
		MinY:=32000;
		MaxX:=-32000;
		MaxY:=-32000;
		for t:=0 to ((LevelEntries^.Vertexes.ObjLength div 4) -1) do begin
			if VertexList^[t].x < MinX then
				MinX:=VertexList^[t].x;
			if VertexList^[t].x > MaxX then
				MaxX:=VertexList^[t].x;
			if VertexList^[t].y < MinY then
				MinY:=VertexList^[t].y;
			if VertexList^[t].y > Maxy then
				MaxY:=VertexList^[t].y;
		end;
		MidX:=(MinX+MaxX) div 2;
		MidY:=(MinY+MaxY) div 2;
		SkillLevel:=' ';
		ScaleX:=(320 / (MaxX - MidX)) * 0.90;
		ScaleY:=(240 / (MaxY - MidY)) * 0.90;
		if ScaleX < ScaleY then
			Scale:=ScaleX
		else
			Scale:=ScaleY;
		Scale:=Scale * ScaleInc;
		IntScale:=Round(Scale * 65536);
		NumLines:=((LevelEntries^.LineDefs.ObjLength div 14) - 1);
		for t:=0 to NumLines do begin
			SetColor(wcBlue);
			case LineDefList^[t].LineDefType of
				1,26..28,31..34:SetColor(wcLtBlue);   {Doors}
			end;
			if ((LineDefList^[t].Attributes and 32) = 32) and ((ViewerMask and 128)=128) then
				SetColor(wcLtGrey);
			x:=(((VertexList^[LineDefList^[t].StartVertex].x-MidX) * IntScale div 65536) + 320)+(XOffset * ScaleInc);
			y:=(((VertexList^[LineDefList^[t].StartVertex].Y-MidY) * (-IntScale) div 65536) + 240)+(YOffset * ScaleInc);
			MoveTo(x,y);
			x:=(((VertexList^[LineDefList^[t].EndVertex].x-MidX) * IntScale div 65536) + 320)+(XOffset * ScaleInc);
			y:=(((VertexList^[LineDefList^[t].EndVertex].Y-MidY) * (-IntScale) div 65536) + 240)+(YOffset * ScaleInc);
			LineTo(x,y);
		end;
		NumThings:=((LevelEntries^.Things.ObjLength div 10) -1);
		for t:=0 to NumThings do begin
			x:=(((ThingList^[t].x-MidX) * IntScale div 65536)+320)+(XOffset * ScaleInc);
			y:=(((ThingList^[t].y-MidY) * (-IntScale) div 65536)+240)+(YOffset * ScaleInc);
			SetColor(wcRed);
			TT:=ThingList^[t].ThingType;
			if (ThingMask=0) or (TT=ThingMask) then begin
				if OnSkillLevel(ThingList^[t].Attributes,ViewerMask) then begin
					if (ViewerMask and 1) = 1 then {Monsters}
						if (TT=$7) or (TT=$9) or (TT=$10) or (TT=$3A) or ((TT > $BB8) and (TT<$BBF)) then begin
							SetColor(wcRed);
							Circle(x,y,ScaleInc);
						end;
					if (ViewerMask and 2) = 2 then begin {Goodies}
						if (TT=$5) or (TT=$6) or (TT=$8) or (TT=$d) or (TT=$26) or (TT=$27) then begin
							SetColor(wcLtGreen);
							Circle(x,y,ScaleInc);
						end;
						if ((TT>$7D6) and (TT<$7EB)) or ((TT>$7FC) and (TT<$802)) then begin
							SetColor(wcLtGreen);
							Circle(x,y,ScaleInc);
						end;
					end;
					if (ViewerMask and 4) = 4 then {Weapons}
						if (TT > $7D0) and (TT<$7D7) then begin
							SetColor(wcYellow);
							Circle(x,y,ScaleInc);
						end;
				end;
			end;
		end;
		OutTextXY(560,1,LevelEntries^.MapID.ObjName);
		str(ScaleInc,TempStr);
		OutTextXY(1,465,'Scale: '+TempStr+'x');
	end;

Procedure TWadMap.SetScale(NewScaleInc,NewXOffset,NewYOffset:word);

	begin
		ScaleInc:=NewScaleInc;
		XOffset:=NewXOffset;
		YOffset:=NewYOffset;
	end;

Function TWadMap.GetThingInArea(x1,y1,x2,y2:word):word;

	var	MidX,MidY,MaxX,MaxY,MinX,MinY:integer;
			ScaleX,ScaleY,Scale:real;
			IntScale:Longint;
			x,y,NumThings,NumLines,gd,gm,t:integer;
			ch,SkillLevel:Char;
			TT:word;

	begin
		MinX:=32000;
		MinY:=32000;
		MaxX:=-32000;
		MaxY:=-32000;
		for t:=0 to ((LevelEntries^.Vertexes.ObjLength div 4) -1) do begin
			if VertexList^[t].x < MinX then
				MinX:=VertexList^[t].x;
			if VertexList^[t].x > MaxX then
				MaxX:=VertexList^[t].x;
			if VertexList^[t].y < MinY then
				MinY:=VertexList^[t].y;
			if VertexList^[t].y > Maxy then
				MaxY:=VertexList^[t].y;
		end;
		MidX:=(MinX+MaxX) div 2;
		MidY:=(MinY+MaxY) div 2;
		SkillLevel:=' ';
		ScaleX:=(320 / (MaxX - MidX)) * 0.90;
		ScaleY:=(240 / (MaxY - MidY)) * 0.90;
		if ScaleX < ScaleY then
			Scale:=ScaleX
		else
			Scale:=ScaleY;
		Scale:=Scale * ScaleInc;
		IntScale:=Round(Scale * 65536);
		NumThings:=((LevelEntries^.Things.ObjLength div 10) -1);
		for t:=0 to NumThings do begin
			x:=(((ThingList^[t].x-MidX) * IntScale div 65536)+320)+(XOffset * ScaleInc);
			y:=(((ThingList^[t].y-MidY) * (-IntScale) div 65536)+240)+(YOffset * ScaleInc);
			if ((x >= x1) and (x <= x2)) and ((y >= y1) and (y <= y2)) then begin
				TT:=ThingList^[t].ThingType;
				if (ThingMask=0) or (TT=ThingMask) then begin
					if (ViewerMask and 1) = 1 then {Monsters}
						if (TT=$7) or (TT=$9) or (TT=$10) or (TT=$3A) or ((TT > $BB8) and (TT<$BBF)) then begin
							GetThingInArea:=TT;
							exit;
						end;
					if (ViewerMask and 2) = 2 then begin {Goodies}
						if (TT=$5) or (TT=$6) or (TT=$8) or (TT=$d) or (TT=$26) or (TT=$27) then begin
							GetThingInArea:=TT;
							exit;
						end;
						if ((TT>$7D6) and (TT<$7EB)) or ((TT>$7FC) and (TT<$802)) then begin
							GetThingInArea:=TT;
							exit;
						end;
					end;
					if (ViewerMask and 4) = 4 then {Weapons}
						if (TT > $7D0) and (TT<$7D7) then begin
							GetThingInArea:=TT;
							exit;
						end;
				end;
			end;
		end;
		GetThingInArea:=0;
	end;

Destructor TWadMap.Done;

	var	TempView,SubView:PGraphView;

	begin
		FreeMem(ThingList,LevelEntries^.Things.ObjLength);
		FreeMem(VertexList,LevelEntries^.Vertexes.ObjLength);
		FreeMem(LineDefList,LevelEntries^.LineDefs.ObjLength);
		Dispose(LevelEntries);
	end;

end.
