1 //**************************************************************************
2 //**
3 //**    ##   ##    ##    ##   ##   ####     ####   ###     ###
4 //**    ##   ##  ##  ##  ##   ##  ##  ##   ##  ##  ####   ####
5 //**     ## ##  ##    ##  ## ##  ##    ## ##    ## ## ## ## ##
6 //**     ## ##  ########  ## ##  ##    ## ##    ## ##  ###  ##
7 //**      ###   ##    ##   ###    ##  ##   ##  ##  ##       ##
8 //**       #    ##    ##    #      ####     ####   ##       ##
9 //**
10 //**    $Id: p_setup.cpp 4331 2010-09-09 19:49:09Z dj_jl $
11 //**
12 //**    Copyright (C) 1999-2006 Jānis Legzdiņš
13 //**
14 //**    This program is free software; you can redistribute it and/or
15 //**  modify it under the terms of the GNU General Public License
16 //**  as published by the Free Software Foundation; either version 2
17 //**  of the License, or (at your option) any later version.
18 //**
19 //**    This program is distributed in the hope that it will be useful,
20 //**  but WITHOUT ANY WARRANTY; without even the implied warranty of
21 //**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22 //**  GNU General Public License for more details.
23 //**
24 //**************************************************************************
25 //**
26 //**    Do all the WAD I/O, get map description, set up initial state and
27 //**  misc. LUTs.
28 //**
29 //**************************************************************************
30 
31 // HEADER FILES ------------------------------------------------------------
32 
33 #include "gamedefs.h"
34 #include "zipstream.h"
35 #ifdef SERVER
36 #include "sv_local.h"
37 #endif
38 
39 // MACROS ------------------------------------------------------------------
40 
41 // Lump order in a map WAD: each map needs a couple of lumps
42 // to provide a complete scene geometry description.
43 enum
44 {
45 	ML_LABEL,		// A separator, name, ExMx or MAPxx
46 	ML_THINGS,		// Monsters, items..
47 	ML_LINEDEFS,	// LineDefs, from editing
48 	ML_SIDEDEFS,	// SideDefs, from editing
49 	ML_VERTEXES,	// Vertices, edited and BSP splits generated
50 	ML_SEGS,		// LineSegs, from LineDefs split by BSP
51 	ML_SSECTORS,	// SubSectors, list of LineSegs
52 	ML_NODES,		// BSP nodes
53 	ML_SECTORS,		// Sectors, from editing
54 	ML_REJECT,		// LUT, sector-sector visibility
55 	ML_BLOCKMAP,	// LUT, motion clipping, walls/grid element
56 	ML_BEHAVIOR		// ACS scripts
57 };
58 
59 //	Lump order from "GL-Friendly Nodes" specs.
60 enum
61 {
62 	ML_GL_LABEL,	// A separator name, GL_ExMx or GL_MAPxx
63 	ML_GL_VERT,		// Extra Vertices
64 	ML_GL_SEGS,		// Segs, from linedefs & minisegs
65 	ML_GL_SSECT,	// SubSectors, list of segs
66 	ML_GL_NODES,	// GL BSP nodes
67 	ML_GL_PVS		// Potentially visible set
68 };
69 
70 //	GL-node version identifiers.
71 #define GL_V2_MAGIC			"gNd2"
72 #define GL_V3_MAGIC			"gNd3"
73 #define GL_V5_MAGIC			"gNd5"
74 #define ZGL_MAGIC			"ZGLN"
75 
76 //	Indicates a GL-specific vertex.
77 #define	GL_VERTEX			0x8000
78 #define	GL_VERTEX_V3		0x40000000
79 #define	GL_VERTEX_V5		0x80000000
80 
81 //	GL-seg flags.
82 #define GL_SEG_FLAG_SIDE	0x0001
83 
84 //	Old subsector flag.
85 #define	NF_SUBSECTOR_OLD	0x8000
86 
87 // TYPES -------------------------------------------------------------------
88 
89 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
90 
91 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
92 
93 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
94 
95 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
96 
97 // PUBLIC DATA DEFINITIONS -------------------------------------------------
98 
99 // PRIVATE DATA DEFINITIONS ------------------------------------------------
100 
101 static VCvarI strict_level_errors("strict_level_errors", "1");
102 static VCvarI build_blockmap("build_blockmap", "0", CVAR_Archive);
103 static VCvarI build_gwa("build_gwa", "0", CVAR_Archive);
104 static VCvarI show_level_load_times("show_level_load_times", "0", CVAR_Archive);
105 
106 // CODE --------------------------------------------------------------------
107 
108 //==========================================================================
109 //
110 //	VLevel::LoadMap
111 //
112 //==========================================================================
113 
LoadMap(VName AMapName)114 void VLevel::LoadMap(VName AMapName)
115 {
116 	guard(VLevel::LoadMap);
117 	bool AuxiliaryMap = false;
118 	int lumpnum;
119 	VName MapLumpName;
120 
121 	double TotalTime = -Sys_Time();
122 	double InitTime = -Sys_Time();
123 	MapName = AMapName;
124 	//	If working with a devlopment map, reload it.
125 	VStr aux_file_name = va("maps/%s.wad", *MapName);
126 	if (FL_FileExists(aux_file_name))
127 	{
128 		lumpnum = W_OpenAuxiliary(aux_file_name);
129 		MapLumpName = W_LumpName(lumpnum);
130 		AuxiliaryMap = true;
131 	}
132 	else
133 	{
134 		//	Find map and GL nodes.
135 		MapLumpName = MapName;
136 		lumpnum = W_CheckNumForName(MapName);
137 		if (lumpnum < 0)
138 		{
139 			Host_Error("Map %s not found\n", *MapName);
140 		}
141 	}
142 
143 	int gl_lumpnum = -100;
144 	int ThingsLump = -1;
145 	int LinesLump = -1;
146 	int SidesLump = -1;
147 	int VertexesLump = -1;
148 	int SectorsLump = -1;
149 	int RejectLump = -1;
150 	int BlockmapLump = -1;
151 	int BehaviorLump = -1;
152 	int DialogueLump = -1;
153 	int CompressedGLNodesLump = -1;
154 	bool UseComprGLNodes = false;
155 	bool NeedNodesBuild = false;
156 	const mapInfo_t& MInfo = P_GetMapInfo(MapName);
157 
158 	//	Check for UDMF map
159 	if (W_LumpName(lumpnum + 1) == NAME_textmap)
160 	{
161 		LevelFlags |= LF_TextMap;
162 		NeedNodesBuild = true;
163 		for (int i = 2; true; i++)
164 		{
165 			VName LName = W_LumpName(lumpnum + i);
166 			if (LName == NAME_endmap)
167 			{
168 				break;
169 			}
170 			if (LName == NAME_None)
171 			{
172 				Host_Error("Map %s is not a valid map", *MapName);
173 			}
174 			if (LName == NAME_behavior)
175 			{
176 				BehaviorLump = lumpnum + i;
177 			}
178 			else if (LName == NAME_blockmap)
179 			{
180 				BlockmapLump = lumpnum + i;
181 			}
182 			else if (LName == NAME_reject)
183 			{
184 				RejectLump = lumpnum + i;
185 			}
186 			else if (LName == NAME_dialogue)
187 			{
188 				DialogueLump = lumpnum + i;
189 			}
190 			else if (LName == NAME_znodes)
191 			{
192 				CompressedGLNodesLump = lumpnum + i;
193 				UseComprGLNodes = true;
194 				NeedNodesBuild = false;
195 			}
196 		}
197 	}
198 	else
199 	{
200 		//	Find all lumps.
201 		int LIdx = lumpnum + 1;
202 		int SubsectorsLump = -1;
203 		if (W_LumpName(LIdx) == NAME_things)
204 		{
205 			ThingsLump = LIdx++;
206 		}
207 		if (W_LumpName(LIdx) == NAME_linedefs)
208 		{
209 			LinesLump = LIdx++;
210 		}
211 		if (W_LumpName(LIdx) == NAME_sidedefs)
212 		{
213 			SidesLump = LIdx++;
214 		}
215 		if (W_LumpName(LIdx) == NAME_vertexes)
216 		{
217 			VertexesLump = LIdx++;
218 		}
219 		if (W_LumpName(LIdx) == NAME_segs)
220 		{
221 			LIdx++;
222 		}
223 		if (W_LumpName(LIdx) == NAME_ssectors)
224 		{
225 			SubsectorsLump = LIdx++;
226 		}
227 		if (W_LumpName(LIdx) == NAME_nodes)
228 		{
229 			LIdx++;
230 		}
231 		if (W_LumpName(LIdx) == NAME_sectors)
232 		{
233 			SectorsLump = LIdx++;
234 		}
235 		if (W_LumpName(LIdx) == NAME_reject)
236 		{
237 			RejectLump = LIdx++;
238 		}
239 		if (W_LumpName(LIdx) == NAME_blockmap)
240 		{
241 			BlockmapLump = LIdx++;
242 		}
243 		//	Determine level format.
244 		if (W_LumpName(LIdx) == NAME_behavior)
245 		{
246 			LevelFlags |= LF_Extended;
247 			BehaviorLump = LIdx++;
248 		}
249 
250 		//	Verify that it's a valid map.
251 		if (ThingsLump == -1 || LinesLump == -1 || SidesLump == -1 ||
252 			VertexesLump == -1 || SectorsLump == -1)
253 		{
254 			Host_Error("Map %s is not a valid map", *MapName);
255 		}
256 
257 		if (SubsectorsLump != -1)
258 		{
259 			VStream* TmpStrm = W_CreateLumpReaderNum(SubsectorsLump);
260 			if (TmpStrm->TotalSize() > 4)
261 			{
262 				char Hdr[4];
263 				TmpStrm->Serialise(Hdr, 4);
264 				if (!VStr::NCmp(Hdr, ZGL_MAGIC, 4))
265 				{
266 					UseComprGLNodes = true;
267 					CompressedGLNodesLump = SubsectorsLump;
268 				}
269 			}
270 			delete TmpStrm;
271 			TmpStrm = NULL;
272 		}
273 	}
274 	InitTime += Sys_Time();
275 
276 	double NodeBuildTime = -Sys_Time();
277 	if (!(LevelFlags & LF_TextMap) && !UseComprGLNodes)
278 	{
279 		gl_lumpnum = FindGLNodes(MapLumpName);
280 #ifdef CLIENT
281 		if (build_gwa)
282 		{
283 			//	If missing GL nodes or VIS data, then build them.
284 			if (gl_lumpnum < lumpnum)
285 			{
286 				W_BuildGLNodes(lumpnum);
287 				gl_lumpnum = FindGLNodes(MapLumpName);
288 			}
289 			else if (W_LumpName(gl_lumpnum + ML_GL_PVS) != NAME_gl_pvs ||
290 				W_LumpLength(gl_lumpnum + ML_GL_PVS) == 0)
291 			{
292 				W_BuildPVS(lumpnum, gl_lumpnum);
293 				lumpnum = W_GetNumForName(MapLumpName);
294 				gl_lumpnum = FindGLNodes(MapLumpName);
295 			}
296 		}
297 #endif
298 		if (gl_lumpnum < lumpnum)
299 		{
300 			if (build_gwa)
301 			{
302 				Host_Error("Map %s is missing GL-Nodes\n", *MapName);
303 			}
304 			else
305 			{
306 				NeedNodesBuild = true;
307 			}
308 		}
309 	}
310 	NodeBuildTime += Sys_Time();
311 
312 	int NumBaseVerts;
313 	double VertexTime = 0;
314 	double SectorsTime = 0;
315 	double LinesTime = 0;
316 	double ThingsTime = 0;
317 	double TranslTime = 0;
318 	double SidesTime = 0;
319 	//	Begin processing map lumps.
320 	if (LevelFlags & LF_TextMap)
321 	{
322 		VertexTime = -Sys_Time();
323 		LoadTextMap(lumpnum + 1, MInfo);
324 		VertexTime += Sys_Time();
325 	}
326 	else
327 	{
328 		// Note: most of this ordering is important
329 		VertexTime = -Sys_Time();
330 		LevelFlags &= ~LF_GLNodesV5;
331 		LoadVertexes(VertexesLump, gl_lumpnum + ML_GL_VERT, NumBaseVerts);
332 		VertexTime += Sys_Time();
333 		SectorsTime = -Sys_Time();
334 		LoadSectors(SectorsLump);
335 		SectorsTime += Sys_Time();
336 		LinesTime = -Sys_Time();
337 		if (!(LevelFlags & LF_Extended))
338 		{
339 			LoadLineDefs1(LinesLump, NumBaseVerts, MInfo);
340 			LinesTime += Sys_Time();
341 			ThingsTime = -Sys_Time();
342 			LoadThings1(ThingsLump);
343 		}
344 		else
345 		{
346 			LoadLineDefs2(LinesLump, NumBaseVerts, MInfo);
347 			LinesTime += Sys_Time();
348 			ThingsTime = -Sys_Time();
349 			LoadThings2(ThingsLump);
350 		}
351 		ThingsTime += Sys_Time();
352 
353 		TranslTime = -Sys_Time();
354 		if (!(LevelFlags & LF_Extended))
355 		{
356 			//	Translate level to Hexen format
357 			GGameInfo->eventTranslateLevel(this);
358 		}
359 		TranslTime += Sys_Time();
360 		//	Set up textures after loading lines because for some Boom line
361 		// specials there can be special meaning of some texture names.
362 		SidesTime = -Sys_Time();
363 		LoadSideDefs(SidesLump);
364 		SidesTime += Sys_Time();
365 	}
366 	double Lines2Time = -Sys_Time();
367 	FinaliseLines();
368 	Lines2Time += Sys_Time();
369 
370 	double NodesTime = -Sys_Time();
371 	if (NeedNodesBuild)
372 	{
373 		BuildNodes();
374 	}
375 	else if (UseComprGLNodes)
376 	{
377 		LoadCompressedGLNodes(CompressedGLNodesLump);
378 	}
379 	else
380 	{
381 		LoadGLSegs(gl_lumpnum + ML_GL_SEGS, NumBaseVerts);
382 		LoadSubsectors(gl_lumpnum + ML_GL_SSECT);
383 		LoadNodes(gl_lumpnum + ML_GL_NODES);
384 		LoadPVS(gl_lumpnum + ML_GL_PVS);
385 	}
386 	NodesTime += Sys_Time();
387 
388 	//	Load blockmap
389 	double BlockMapTime = -Sys_Time();
390 	LoadBlockMap(BlockmapLump);
391 	BlockMapTime += Sys_Time();
392 
393 	//	Load reject table.
394 	double RejectTime = -Sys_Time();
395 	LoadReject(RejectLump);
396 	RejectTime += Sys_Time();
397 
398 	//	ACS object code
399 	double AcsTime = -Sys_Time();
400 	LoadACScripts(BehaviorLump);
401 	AcsTime += Sys_Time();
402 
403 	double GroupLinesTime = -Sys_Time();
404 	GroupLines();
405 	GroupLinesTime += Sys_Time();
406 
407 	double FloodZonesTime = -Sys_Time();
408 	FloodZones();
409 	FloodZonesTime += Sys_Time();
410 
411 	double ConvTime = -Sys_Time();
412 	//	Load conversations.
413 	LoadRogueConScript(GGameInfo->GenericConScript, -1, GenericSpeeches,
414 		NumGenericSpeeches);
415 	if (DialogueLump >= 0)
416 	{
417 		LoadRogueConScript(NAME_None, DialogueLump, LevelSpeeches,
418 			NumLevelSpeeches);
419 	}
420 	else
421 	{
422 		LoadRogueConScript(GGameInfo->eventGetConScriptName(MapName), -1,
423 			LevelSpeeches, NumLevelSpeeches);
424 	}
425 	ConvTime += Sys_Time();
426 
427 	//	Set up polyobjs, slopes, 3D floors and some other static stuff.
428 	double SpawnWorldTime = -Sys_Time();
429 	GGameInfo->eventSpawnWorld(this);
430 	HashLines();
431 	SpawnWorldTime += Sys_Time();
432 	double InitPolysTime = -Sys_Time();
433 	InitPolyobjs();	// Initialise the polyobjs
434 	InitPolysTime += Sys_Time();
435 
436 	double MinMaxTime = -Sys_Time();
437 	//	We need this for client.
438 	for (int i = 0; i < NumSectors; i++)
439 	{
440 		CalcSecMinMaxs(&Sectors[i]);
441 	}
442 	MinMaxTime += Sys_Time();
443 
444 	double WallShadesTime = -Sys_Time();
445 	for (int i = 0; i < NumLines; i++)
446 	{
447 		line_t* Line = Lines + i;
448 		if (!Line->normal.x)
449 		{
450 			Sides[Line->sidenum[0]].Light = MInfo.HorizWallShade;
451 			if (Line->sidenum[1] >= 0)
452 			{
453 				Sides[Lines[i].sidenum[1]].Light = MInfo.HorizWallShade;
454 			}
455 		}
456 		else if (!Line->normal.y)
457 		{
458 			Sides[Line->sidenum[0]].Light = MInfo.VertWallShade;
459 			if (Line->sidenum[1] >= 0)
460 			{
461 				Sides[Lines[i].sidenum[1]].Light = MInfo.VertWallShade;
462 			}
463 		}
464 	}
465 	WallShadesTime += Sys_Time();
466 
467 	double RepBaseTime = -Sys_Time();
468 	CreateRepBase();
469 	RepBaseTime += Sys_Time();
470 
471 	//
472 	// End of map lump processing
473 	//
474 	if (AuxiliaryMap)
475 	{
476 		// Close the auxiliary file.
477 		W_CloseAuxiliary();
478 	}
479 
480 	TotalTime += Sys_Time();
481 	if (show_level_load_times)
482 	{
483 		GCon->Logf("-------");
484 		GCon->Logf("Level loadded in %f", TotalTime);
485 		GCon->Logf("Initialisation   %f", InitTime);
486 		GCon->Logf("Node build       %f", NodeBuildTime);
487 		GCon->Logf("Vertexes         %f", VertexTime);
488 		GCon->Logf("Sectors          %f", SectorsTime);
489 		GCon->Logf("Lines            %f", LinesTime);
490 		GCon->Logf("Things           %f", ThingsTime);
491 		GCon->Logf("Translation      %f", TranslTime);
492 		GCon->Logf("Sides            %f", SidesTime);
493 		GCon->Logf("Lines 2          %f", Lines2Time);
494 		GCon->Logf("Nodes            %f", NodesTime);
495 		GCon->Logf("Block map        %f", BlockMapTime);
496 		GCon->Logf("Reject           %f", RejectTime);
497 		GCon->Logf("ACS              %f", AcsTime);
498 		GCon->Logf("Group lines      %f", GroupLinesTime);
499 		GCon->Logf("Flood zones      %f", FloodZonesTime);
500 		GCon->Logf("Conversations    %f", ConvTime);
501 		GCon->Logf("Spawn world      %f", SpawnWorldTime);
502 		GCon->Logf("Polyobjs         %f", InitPolysTime);
503 		GCon->Logf("Sector minmaxs   %f", MinMaxTime);
504 		GCon->Logf("Wall shades      %f", WallShadesTime);
505 		GCon->Logf("");
506 	}
507 	unguard;
508 }
509 
510 //==========================================================================
511 //
512 //  VLevel::FindGLNodes
513 //
514 //==========================================================================
515 
FindGLNodes(VName name) const516 int VLevel::FindGLNodes(VName name) const
517 {
518 	guard(VLevel::FindGLNodes);
519 	if (VStr::Length(*name) < 6)
520 	{
521 		return W_CheckNumForName(VName(va("gl_%s", *name), VName::AddLower8));
522 	}
523 
524 	//	Long map name, check GL_LEVEL lumps.
525 	for (int Lump = W_IterateNS(-1, WADNS_Global); Lump >= 0;
526 		Lump = W_IterateNS(Lump, WADNS_Global))
527 	{
528 		if (W_LumpName(Lump) != NAME_gl_level)
529 		{
530 			continue;
531 		}
532 		if (W_LumpLength(Lump) < 12)
533 		{
534 			//	Lump is too short.
535 			continue;
536 		}
537 		char Buf[16];
538 		VStream* Strm = W_CreateLumpReaderNum(Lump);
539 		Strm->Serialise(Buf, Strm->TotalSize() < 16 ? Strm->TotalSize() : 16);
540 		delete Strm;
541 		Strm = NULL;
542 		if (memcmp(Buf, "LEVEL=", 6))
543 		{
544 			//	LEVEL keyword expected, but missing.
545 			continue;
546 		}
547 		for (int i = 11; i < 14; i++)
548 		{
549 			if (Buf[i] == '\n' || Buf[i] == '\r')
550 			{
551 				Buf[i] = 0;
552 				break;
553 			}
554 		}
555 		Buf[14] = 0;
556 		if (!VStr::ICmp(Buf + 6, *name))
557 		{
558 			return Lump;
559 		}
560 	}
561 	return -1;
562 	unguard;
563 }
564 
565 //==========================================================================
566 //
567 //	VLevel::LoadVertexes
568 //
569 //==========================================================================
570 
LoadVertexes(int Lump,int GLLump,int & NumBaseVerts)571 void VLevel::LoadVertexes(int Lump, int GLLump, int& NumBaseVerts)
572 {
573 	guard(VLevel::LoadVertexes);
574 	int GlFormat = 0;
575 	if (GLLump >= 0)
576 	{
577 		//	Read header of the GL vertexes lump and determinte GL vertex format.
578 		char Magic[4];
579 		W_ReadFromLump(GLLump, Magic, 0, 4);
580 		GlFormat = !VStr::NCmp((char*)Magic, GL_V2_MAGIC, 4) ? 2 :
581 			!VStr::NCmp((char*)Magic, GL_V5_MAGIC, 4) ? 5 : 1;
582 		if (GlFormat ==  5)
583 		{
584 			LevelFlags |= LF_GLNodesV5;
585 		}
586 	}
587 
588 	//	Determine number of vertexes: total lump length / vertex record length.
589 	NumBaseVerts = W_LumpLength(Lump) / 4;
590 	int NumGLVerts = GlFormat == 0 ? 0 : GlFormat == 1 ?
591 		(W_LumpLength(GLLump) / 4) : ((W_LumpLength(GLLump) - 4) / 8);
592 	NumVertexes = NumBaseVerts + NumGLVerts;
593 
594 	//	Allocate memory for vertexes.
595 	Vertexes = new vertex_t[NumVertexes];
596 
597 	//	Load base vertexes.
598 	VStream* Strm = W_CreateLumpReaderNum(Lump);
599 	vertex_t* pDst = Vertexes;
600 	for (int i = 0; i < NumBaseVerts; i++, pDst++)
601 	{
602 		vint16 x, y;
603 		*Strm << x << y;
604 		*pDst = TVec(x, y, 0);
605 	}
606 	delete Strm;
607 	Strm = NULL;
608 
609 	if (GLLump >= 0)
610 	{
611 		//	Load GL vertexes.
612 		Strm = W_CreateLumpReaderNum(GLLump);
613 		if (GlFormat == 1)
614 		{
615 			//	GL version 1 vertexes, same as normal ones.
616 			for (int i = 0; i < NumGLVerts; i++, pDst++)
617 			{
618 				vint16 x, y;
619 				*Strm << x << y;
620 				*pDst = TVec(x, y, 0);
621 			}
622 		}
623 		else
624 		{
625 			//	GL version 2 or greater vertexes, as fixed point.
626 			Strm->Seek(4);
627 			for (int i = 0; i < NumGLVerts; i++, pDst++)
628 			{
629 				vint32 x, y;
630 				*Strm << x << y;
631 				*pDst = TVec(x / 65536.0, y / 65536.0, 0);
632 			}
633 		}
634 		delete Strm;
635 		Strm = NULL;
636 	}
637 	unguard;
638 }
639 
640 //==========================================================================
641 //
642 //	VLevel::LoadSectors
643 //
644 //==========================================================================
645 
LoadSectors(int Lump)646 void VLevel::LoadSectors(int Lump)
647 {
648 	guard(VLevel::LoadSectors);
649 	//	Allocate memory for sectors.
650 	NumSectors = W_LumpLength(Lump) / 26;
651 	Sectors = new sector_t[NumSectors];
652 	memset(Sectors, 0, sizeof(sector_t) * NumSectors);
653 
654 	//	Load sectors.
655 	VStream* Strm = W_CreateLumpReaderNum(Lump);
656 	sector_t* ss = Sectors;
657 	for (int i = 0; i < NumSectors; i++, ss++)
658 	{
659 		//	Read data.
660 		vint16 floorheight, ceilingheight, lightlevel, special, tag;
661 		char floorpic[8];
662 		char ceilingpic[8];
663 		*Strm << floorheight << ceilingheight;
664 		Strm->Serialise(floorpic, 8);
665 		Strm->Serialise(ceilingpic, 8);
666 		*Strm << lightlevel << special << tag;
667 
668 		//	Floor
669 		ss->floor.Set(TVec(0, 0, 1), floorheight);
670 		ss->floor.TexZ = floorheight;
671 		ss->floor.pic = TexNumForName(floorpic, TEXTYPE_Flat);
672 		ss->floor.xoffs = 0;
673 		ss->floor.yoffs = 0;
674 		ss->floor.XScale = 1.0;
675 		ss->floor.YScale = 1.0;
676 		ss->floor.Angle = 0.0;
677 		ss->floor.minz = floorheight;
678 		ss->floor.maxz = floorheight;
679 		ss->floor.Alpha = 1.0;
680 		ss->floor.MirrorAlpha = 1.0;
681 		ss->floor.LightSourceSector = -1;
682 
683 		//	Ceiling
684 		ss->ceiling.Set(TVec(0, 0, -1), -ceilingheight);
685 		ss->ceiling.TexZ = ceilingheight;
686 		ss->ceiling.pic = TexNumForName(ceilingpic, TEXTYPE_Flat);
687 		ss->ceiling.xoffs = 0;
688 		ss->ceiling.yoffs = 0;
689 		ss->ceiling.XScale = 1.0;
690 		ss->ceiling.YScale = 1.0;
691 		ss->ceiling.Angle = 0.0;
692 		ss->ceiling.minz = ceilingheight;
693 		ss->ceiling.maxz = ceilingheight;
694 		ss->ceiling.Alpha = 1.0;
695 		ss->ceiling.MirrorAlpha = 1.0;
696 		ss->ceiling.LightSourceSector = -1;
697 
698 		//	Params
699 		ss->params.lightlevel = lightlevel;
700 		ss->params.LightColour = 0x00ffffff;
701 		//	Region
702 		sec_region_t* region = new sec_region_t;
703 		memset(region, 0, sizeof(*region));
704 		region->floor = &ss->floor;
705 		region->ceiling = &ss->ceiling;
706 		region->params = &ss->params;
707 		ss->topregion = region;
708 		ss->botregion = region;
709 
710 		ss->special = special;
711 		ss->tag = tag;
712 
713 		ss->seqType = -1;	// default seqType
714 		ss->Gravity = 1.0;	// default sector gravity of 1.0
715 		ss->Zone = -1;
716 	}
717 	delete Strm;
718 	Strm = NULL;
719 	HashSectors();
720 	unguard;
721 }
722 
723 //==========================================================================
724 //
725 //	VLevel::CreateSides
726 //
727 //==========================================================================
728 
CreateSides()729 void VLevel::CreateSides()
730 {
731 	guard(VLevel::CreateSides);
732 	//	Perform side index and two-sided flag checks and count number of
733 	// sides needed.
734 	int NumNewSides = 0;
735 	line_t* Line = Lines;
736 	for (int i = 0; i < NumLines; i++, Line++)
737 	{
738 		if (Line->sidenum[0] == -1)
739 		{
740 			if (strict_level_errors)
741 			{
742 				Host_Error("Bad WAD: Line %d has no front side", i);
743 			}
744 			else
745 			{
746 				GCon->Logf("Bad WAD: Line %d has no front side", i);
747 				Line->sidenum[0] = 0;
748 			}
749 		}
750 		if (Line->sidenum[0] < 0 || Line->sidenum[0] >= NumSides)
751 		{
752 			Host_Error("Bad side-def index %d", Line->sidenum[0]);
753 		}
754 		NumNewSides++;
755 
756 		if (Line->sidenum[1] != -1)
757 		{
758 			if (Line->sidenum[1] < 0 || Line->sidenum[1] >= NumSides)
759 			{
760 				Host_Error("Bad side-def index %d", Line->sidenum[1]);
761 			}
762 			// Just a warning
763 			if (!(Line->flags & ML_TWOSIDED))
764 			{
765 				GCon->Logf("Bad WAD: Line %d is two-sided but has no TWO-SIDED "
766 					"flag set", i);
767 			}
768 			NumNewSides++;
769 		}
770 		else
771 		{
772 			if (Line->flags & ML_TWOSIDED)
773 			{
774 				if (strict_level_errors)
775 				{
776 					Host_Error("Bad WAD: Line %d is marked as TWO-SIDED but has "
777 						"only one side", i);
778 				}
779 				else
780 				{
781 					GCon->Logf("Bad WAD: Line %d is marked as TWO-SIDED but has "
782 						"only one side", i);
783 					Line->flags &= ~ML_TWOSIDED;
784 				}
785 			}
786 		}
787 	}
788 
789 	//	Allocate memory for side defs.
790 	Sides = new side_t[NumNewSides];
791 	memset(Sides, 0, sizeof(side_t) * NumNewSides);
792 
793 	int CurrentSide = 0;
794 	Line = Lines;
795 	for (int i = 0; i < NumLines; i++, Line++)
796 	{
797 		Sides[CurrentSide].BottomTexture = Line->sidenum[0];
798 		Sides[CurrentSide].LineNum = i;
799 		Line->sidenum[0] = CurrentSide;
800 		CurrentSide++;
801 		if (Line->sidenum[1] != -1)
802 		{
803 			Sides[CurrentSide].BottomTexture = Line->sidenum[1];
804 			Sides[CurrentSide].LineNum = i;
805 			Line->sidenum[1] = CurrentSide;
806 			CurrentSide++;
807 		}
808 
809 		//	Assign line specials to sidedefs midtexture and arg1 to toptexture.
810 		if (Line->special == LNSPEC_StaticInit && Line->arg2 != 1)
811 		{
812 			continue;
813 		}
814 		Sides[Line->sidenum[0]].MidTexture = Line->special;
815 		Sides[Line->sidenum[0]].TopTexture = Line->arg1;
816 	}
817 	check(CurrentSide == NumNewSides);
818 
819 	NumSides = NumNewSides;
820 	unguard;
821 }
822 
823 //==========================================================================
824 //
825 //	VLevel::LoadSideDefs
826 //
827 //==========================================================================
828 
LoadSideDefs(int Lump)829 void VLevel::LoadSideDefs(int Lump)
830 {
831 	guard(VLevel::LoadSideDefs);
832 	NumSides = W_LumpLength(Lump) / 30;
833 	CreateSides();
834 
835 	//	Load data.
836 	VStream* Strm = W_CreateLumpReaderNum(Lump);
837 	side_t* sd = Sides;
838 	for (int i = 0; i < NumSides; i++, sd++)
839 	{
840 		Strm->Seek(sd->BottomTexture * 30);
841 		vint16 textureoffset;
842 		vint16 rowoffset;
843 		char toptexture[8];
844 		char bottomtexture[8];
845 		char midtexture[8];
846 		vint16 sector;
847 		*Strm << textureoffset << rowoffset;
848 		Strm->Serialise(toptexture, 8);
849 		Strm->Serialise(bottomtexture, 8);
850 		Strm->Serialise(midtexture, 8);
851 		*Strm << sector;
852 
853 		if (sector < 0 || sector >= NumSectors)
854 		{
855 			Host_Error("Bad sector index %d", sector);
856 		}
857 
858 		sd->TopTextureOffset = textureoffset;
859 		sd->BotTextureOffset = textureoffset;
860 		sd->MidTextureOffset = textureoffset;
861 		sd->TopRowOffset = rowoffset;
862 		sd->BotRowOffset = rowoffset;
863 		sd->MidRowOffset = rowoffset;
864 		sd->Sector = &Sectors[sector];
865 
866 		switch (sd->MidTexture)
867 		{
868 		case LNSPEC_LineTranslucent:
869 			//	In BOOM midtexture can be translucency table lump name.
870 			sd->MidTexture = GTextureManager.CheckNumForName(
871 				VName(midtexture, VName::AddLower8),
872 				TEXTYPE_Wall, true, true);
873 			if (sd->MidTexture == -1)
874 			{
875 				sd->MidTexture = 0;
876 			}
877 			sd->TopTexture = TexNumForName(toptexture, TEXTYPE_Wall);
878 			sd->BottomTexture = TexNumForName(bottomtexture, TEXTYPE_Wall);
879 			break;
880 
881 		case LNSPEC_TransferHeights:
882 			sd->MidTexture = TexNumForName(midtexture, TEXTYPE_Wall, true);
883 			sd->TopTexture = TexNumForName(toptexture, TEXTYPE_Wall, true);
884 			sd->BottomTexture = TexNumForName(bottomtexture, TEXTYPE_Wall, true);
885 			break;
886 
887 		case LNSPEC_StaticInit:
888 			{
889 				bool HaveCol;
890 				bool HaveFade;
891 				vuint32 Col;
892 				vuint32 Fade;
893 				sd->MidTexture = TexNumForName(midtexture, TEXTYPE_Wall);
894 				int TmpTop = TexNumOrColour(toptexture, TEXTYPE_Wall,
895 					HaveCol, Col);
896 				sd->BottomTexture = TexNumOrColour(bottomtexture, TEXTYPE_Wall,
897 					HaveFade, Fade);
898 				if (HaveCol || HaveFade)
899 				{
900 					for (int j = 0; j < NumSectors; j++)
901 					{
902 						if (Sectors[j].tag == sd->TopTexture)
903 						{
904 							if (HaveCol)
905 							{
906 								Sectors[j].params.LightColour = Col;
907 							}
908 							if (HaveFade)
909 							{
910 								Sectors[j].params.Fade = Fade;
911 							}
912 						}
913 					}
914 				}
915 				sd->TopTexture = TmpTop;
916 			}
917 			break;
918 
919 		default:
920 			sd->MidTexture = TexNumForName(midtexture, TEXTYPE_Wall);
921 			sd->TopTexture = TexNumForName(toptexture, TEXTYPE_Wall);
922 			sd->BottomTexture = TexNumForName(bottomtexture, TEXTYPE_Wall);
923 			break;
924 		}
925 	}
926 	delete Strm;
927 	Strm = NULL;
928 	unguard;
929 }
930 
931 //==========================================================================
932 //
933 //  VLevel::LoadLineDefs1
934 //
935 //  For Doom and Heretic
936 //
937 //==========================================================================
938 
LoadLineDefs1(int Lump,int NumBaseVerts,const mapInfo_t & MInfo)939 void VLevel::LoadLineDefs1(int Lump, int NumBaseVerts, const mapInfo_t& MInfo)
940 {
941 	guard(VLevel::LoadLineDefs1);
942 	NumLines = W_LumpLength(Lump) / 14;
943 	Lines = new line_t[NumLines];
944 	memset(Lines, 0, sizeof(line_t) * NumLines);
945 
946 	VStream* Strm = W_CreateLumpReaderNum(Lump);
947 	line_t* ld = Lines;
948 	for (int i = 0; i < NumLines; i++, ld++)
949 	{
950 		vint16 v1, v2, flags, special, tag;
951 		vuint16 side0, side1;
952 		*Strm << v1 << v2 << flags << special << tag << side0 << side1;
953 
954 		if (v1 < 0 || v1 >= NumBaseVerts)
955 		{
956 			Host_Error("Bad vertex index %d", v1);
957 		}
958 		if (v2 < 0 || v2 >= NumBaseVerts)
959 		{
960 			Host_Error("Bad vertex index %d", v2);
961 		}
962 
963 		ld->flags = flags;
964 		ld->special = special;
965 		ld->arg1 = tag;
966 		ld->v1 = &Vertexes[v1];
967 		ld->v2 = &Vertexes[v2];
968 		ld->sidenum[0] = side0 == 0xffff ? -1 : side0;
969 		ld->sidenum[1] = side1 == 0xffff ? -1 : side1;
970 
971 		ld->alpha = 1.0;
972 		ld->LineTag = -1;
973 
974 		if (MInfo.Flags & MAPINFOF_ClipMidTex)
975 		{
976 			ld->flags |= ML_CLIP_MIDTEX;
977 		}
978 		if (MInfo.Flags & MAPINFOF_WrapMidTex)
979 		{
980 			ld->flags |= ML_WRAP_MIDTEX;
981 		}
982 	}
983 	delete Strm;
984 	Strm = NULL;
985 	unguard;
986 }
987 
988 //==========================================================================
989 //
990 //  VLevel::LoadLineDefs2
991 //
992 //  For Hexen
993 //
994 //==========================================================================
995 
LoadLineDefs2(int Lump,int NumBaseVerts,const mapInfo_t & MInfo)996 void VLevel::LoadLineDefs2(int Lump, int NumBaseVerts, const mapInfo_t& MInfo)
997 {
998 	guard(VLevel::LoadLineDefs2);
999 	NumLines = W_LumpLength(Lump) / 16;
1000 	Lines = new line_t[NumLines];
1001 	memset(Lines, 0, sizeof(line_t) * NumLines);
1002 
1003 	VStream* Strm = W_CreateLumpReaderNum(Lump);
1004 	line_t* ld = Lines;
1005 	for (int i = 0; i < NumLines; i++, ld++)
1006 	{
1007 		vint16 v1, v2, flags;
1008 		vuint8 special, arg1, arg2, arg3, arg4, arg5;
1009 		vuint16 side0, side1;
1010 		*Strm << v1 << v2 << flags << special << arg1 << arg2 << arg3 << arg4
1011 			<< arg5 << side0 << side1;
1012 
1013 		if (v1 < 0 || v1 >= NumBaseVerts)
1014 		{
1015 			Host_Error("Bad vertex index %d", v1);
1016 		}
1017 		if (v2 < 0 || v2 >= NumBaseVerts)
1018 		{
1019 			Host_Error("Bad vertex index %d", v2);
1020 		}
1021 
1022 		ld->flags = flags & ~ML_SPAC_MASK;
1023 		int Spac = (flags & ML_SPAC_MASK) >> ML_SPAC_SHIFT;
1024 		if (Spac == 7)
1025 		{
1026 			ld->SpacFlags = SPAC_Impact | SPAC_PCross;
1027 		}
1028 		else
1029 		{
1030 			ld->SpacFlags = 1 << Spac;
1031 		}
1032 
1033 		// New line special info ...
1034 		ld->special = special;
1035 		ld->arg1 = arg1;
1036 		ld->arg2 = arg2;
1037 		ld->arg3 = arg3;
1038 		ld->arg4 = arg4;
1039 		ld->arg5 = arg5;
1040 
1041 		ld->v1 = &Vertexes[v1];
1042 		ld->v2 = &Vertexes[v2];
1043 		ld->sidenum[0] = side0 == 0xffff ? -1 : side0;
1044 		ld->sidenum[1] = side1 == 0xffff ? -1 : side1;
1045 
1046 		ld->alpha = 1.0;
1047 		ld->LineTag = -1;
1048 
1049 		if (MInfo.Flags & MAPINFOF_ClipMidTex)
1050 		{
1051 			ld->flags |= ML_CLIP_MIDTEX;
1052 		}
1053 		if (MInfo.Flags & MAPINFOF_WrapMidTex)
1054 		{
1055 			ld->flags |= ML_WRAP_MIDTEX;
1056 		}
1057 	}
1058 	delete Strm;
1059 	Strm = NULL;
1060 	unguard;
1061 }
1062 
1063 //==========================================================================
1064 //
1065 //	VLevel::FinaliseLines
1066 //
1067 //==========================================================================
1068 
FinaliseLines()1069 void VLevel::FinaliseLines()
1070 {
1071 	guard(VLevel::FinaliseLines);
1072 	line_t* Line = Lines;
1073 	for (int i = 0; i < NumLines; i++, Line++)
1074 	{
1075 		//	Calculate line's plane, slopetype, etc.
1076 		CalcLine(Line);
1077 
1078 		//	Set up sector references.
1079 		Line->frontsector = Sides[Line->sidenum[0]].Sector;
1080 		if (Line->sidenum[1] != -1)
1081 		{
1082 			Line->backsector = Sides[Line->sidenum[1]].Sector;
1083 		}
1084 		else
1085 		{
1086 			Line->backsector = NULL;
1087 		}
1088 	}
1089 	unguard;
1090 }
1091 
1092 //==========================================================================
1093 //
1094 //  VLevel::LoadGLSegs
1095 //
1096 //==========================================================================
1097 
LoadGLSegs(int Lump,int NumBaseVerts)1098 void VLevel::LoadGLSegs(int Lump, int NumBaseVerts)
1099 {
1100 	guard(VLevel::LoadGLSegs);
1101 	vertex_t* GLVertexes = Vertexes + NumBaseVerts;
1102 	int NumGLVertexes = NumVertexes - NumBaseVerts;
1103 
1104 	//	Determine format of the segs data.
1105 	int Format;
1106 	vuint32 GLVertFlag;
1107 	if (LevelFlags & LF_GLNodesV5)
1108 	{
1109 		Format = 5;
1110 		NumSegs = W_LumpLength(Lump) / 16;
1111 		GLVertFlag = GL_VERTEX_V5;
1112 	}
1113 	else
1114 	{
1115 		char Header[4];
1116 		W_ReadFromLump(Lump, Header, 0, 4);
1117 		if (!VStr::NCmp(Header, GL_V3_MAGIC, 4))
1118 		{
1119 			Format = 3;
1120 			NumSegs = (W_LumpLength(Lump) - 4) / 16;
1121 			GLVertFlag = GL_VERTEX_V3;
1122 		}
1123 		else
1124 		{
1125 			Format = 1;
1126 			NumSegs = W_LumpLength(Lump) / 10;
1127 			GLVertFlag = GL_VERTEX;
1128 		}
1129 	}
1130 
1131 	//	Allocate memory for segs data.
1132 	Segs = new seg_t[NumSegs];
1133 	memset(Segs, 0, sizeof(seg_t) * NumSegs);
1134 
1135 	//	Read data.
1136 	VStream* Strm = W_CreateLumpReaderNum(Lump);
1137 	if (Format == 3)
1138 	{
1139 		Strm->Seek(4);
1140 	}
1141 	seg_t* li = Segs;
1142 	for (int i = 0; i < NumSegs; i++, li++)
1143 	{
1144 		vuint32 v1num;
1145 		vuint32 v2num;
1146 		vint16 linedef;	// -1 for minisegs
1147 		vint16 side;
1148 
1149 		if (Format < 3)
1150 		{
1151 			vuint16 v1, v2;
1152 			vint16 partner;	// -1 on one-sided walls
1153 			*Strm << v1 << v2 << linedef << side << partner;
1154 			v1num = v1;
1155 			v2num = v2;
1156 		}
1157 		else
1158 		{
1159 			vuint32 v1, v2;
1160 			vint16 flags;
1161 			vint32 partner;	// -1 on one-sided walls
1162 			*Strm << v1 << v2 << linedef << flags << partner;
1163 			v1num = v1;
1164 			v2num = v2;
1165 			side = flags & GL_SEG_FLAG_SIDE;
1166 		}
1167 
1168 		if (v1num & GLVertFlag)
1169 		{
1170 			v1num ^= GLVertFlag;
1171 			if (v1num >= (vuint32)NumGLVertexes)
1172 				Host_Error("Bad GL vertex index %d", v1num);
1173 			li->v1 = &GLVertexes[v1num];
1174 		}
1175 		else
1176 		{
1177 			if (v1num >= (vuint32)NumVertexes)
1178 				Host_Error("Bad vertex index %d", v1num);
1179 			li->v1 = &Vertexes[v1num];
1180 		}
1181 		if (v2num & GLVertFlag)
1182 		{
1183 			v2num ^= GLVertFlag;
1184 			if (v2num >= (vuint32)NumGLVertexes)
1185 				Host_Error("Bad GL vertex index %d", v2num);
1186 			li->v2 = &GLVertexes[v2num];
1187 		}
1188 		else
1189 		{
1190 			if (v2num >= (vuint32)NumVertexes)
1191 				Host_Error("Bad vertex index %d", v2num);
1192 			li->v2 = &Vertexes[v2num];
1193 		}
1194 
1195 		if (linedef >= 0)
1196 		{
1197 			line_t* ldef = &Lines[linedef];
1198 			li->linedef = ldef;
1199 			li->sidedef = &Sides[ldef->sidenum[side]];
1200 			li->frontsector = Sides[ldef->sidenum[side]].Sector;
1201 
1202 			if (ldef->flags & ML_TWOSIDED)
1203 			{
1204 				li->backsector = Sides[ldef->sidenum[side ^ 1]].Sector;
1205 			}
1206 
1207 			if (side)
1208 			{
1209 				li->offset = Length(*li->v1 - *ldef->v2);
1210 			}
1211 			else
1212 			{
1213 				li->offset = Length(*li->v1 - *ldef->v1);
1214 			}
1215 			li->length = Length(*li->v2 - *li->v1);
1216 			li->side = side;
1217 		}
1218 
1219 		//	Partner is not used
1220 
1221 		//	Calc seg's plane params
1222 		CalcSeg(li);
1223 	}
1224 	delete Strm;
1225 	Strm = NULL;
1226 	unguard;
1227 }
1228 
1229 //==========================================================================
1230 //
1231 //  VLevel::LoadSubsectors
1232 //
1233 //==========================================================================
1234 
LoadSubsectors(int Lump)1235 void VLevel::LoadSubsectors(int Lump)
1236 {
1237 	guard(VLevel::LoadSubsectors);
1238 	//	Determine format of the subsectors data.
1239 	int Format;
1240 	if (LevelFlags & LF_GLNodesV5)
1241 	{
1242 		Format = 5;
1243 		NumSubsectors = W_LumpLength(Lump) / 8;
1244 	}
1245 	else
1246 	{
1247 		char Header[4];
1248 		W_ReadFromLump(Lump, Header, 0, 4);
1249 		if (!VStr::NCmp(Header, GL_V3_MAGIC, 4))
1250 		{
1251 			Format = 3;
1252 			NumSubsectors = (W_LumpLength(Lump) - 4) / 8;
1253 		}
1254 		else
1255 		{
1256 			Format = 1;
1257 			NumSubsectors = W_LumpLength(Lump) / 4;
1258 		}
1259 	}
1260 
1261 	//	Allocate memory for subsectors.
1262 	Subsectors = new subsector_t[NumSubsectors];
1263 	memset(Subsectors, 0, sizeof(subsector_t) * NumSubsectors);
1264 
1265 	//	Read data.
1266 	VStream* Strm = W_CreateLumpReaderNum(Lump);
1267 	if (Format == 3)
1268 	{
1269 		Strm->Seek(4);
1270 	}
1271 	subsector_t* ss = Subsectors;
1272 	for (int i = 0; i < NumSubsectors; i++, ss++)
1273 	{
1274 		if (Format < 3)
1275 		{
1276 			vuint16 numsegs, firstseg;
1277 			*Strm << numsegs << firstseg;
1278 			ss->numlines = numsegs;
1279 			ss->firstline = firstseg;
1280 		}
1281 		else
1282 		{
1283 			vint32 numsegs, firstseg;
1284 			*Strm << numsegs << firstseg;
1285 			ss->numlines = numsegs;
1286 			ss->firstline = firstseg;
1287 		}
1288 
1289 		if (ss->firstline < 0 || ss->firstline >= NumSegs)
1290 			Host_Error("Bad seg index %d", ss->firstline);
1291 		if (ss->numlines <= 0 || ss->firstline + ss->numlines > NumSegs)
1292 			Host_Error("Bad segs range %d %d", ss->firstline, ss->numlines);
1293 
1294 			// look up sector number for each subsector
1295 		seg_t* seg = &Segs[ss->firstline];
1296 		for (int j = 0; j < ss->numlines; j++)
1297 		{
1298 			if (seg[j].linedef)
1299 			{
1300 				ss->sector = seg[j].sidedef->Sector;
1301 				ss->seclink = ss->sector->subsectors;
1302 				ss->sector->subsectors = ss;
1303 				break;
1304 			}
1305 		}
1306 		if (!ss->sector)
1307 		{
1308 			Host_Error("Subsector %d without sector", i);
1309 		}
1310 	}
1311 	delete Strm;
1312 	Strm = NULL;
1313 	unguard;
1314 }
1315 
1316 //==========================================================================
1317 //
1318 //  VLevel::LoadNodes
1319 //
1320 //==========================================================================
1321 
LoadNodes(int Lump)1322 void VLevel::LoadNodes(int Lump)
1323 {
1324 	guard(VLevel::LoadNodes);
1325 	if (LevelFlags & LF_GLNodesV5)
1326 	{
1327 		NumNodes = W_LumpLength(Lump) / 32;
1328 	}
1329 	else
1330 	{
1331 		NumNodes = W_LumpLength(Lump) / 28;
1332 	}
1333 	Nodes = new node_t[NumNodes];
1334 	memset(Nodes, 0, sizeof(node_t) * NumNodes);
1335 
1336 	VStream* Strm = W_CreateLumpReaderNum(Lump);
1337 	node_t* no = Nodes;
1338 	for (int i = 0; i < NumNodes; i++, no++)
1339 	{
1340 		vint16 x, y, dx, dy;
1341 		vint16 bbox[2][4];
1342 		vuint32 children[2];
1343 		*Strm << x << y << dx << dy
1344 			<< bbox[0][0] << bbox[0][1] << bbox[0][2] << bbox[0][3]
1345 			<< bbox[1][0] << bbox[1][1] << bbox[1][2] << bbox[1][3];
1346 		if (LevelFlags & LF_GLNodesV5)
1347 		{
1348 			*Strm << children[0] << children[1];
1349 		}
1350 		else
1351 		{
1352 			vuint16 child0, child1;
1353 			*Strm << child0 << child1;
1354 			children[0] = child0;
1355 			if (children[0] & NF_SUBSECTOR_OLD)
1356 				children[0] ^= NF_SUBSECTOR_OLD | NF_SUBSECTOR;
1357 			children[1] = child1;
1358 			if (children[1] & NF_SUBSECTOR_OLD)
1359 				children[1] ^= NF_SUBSECTOR_OLD | NF_SUBSECTOR;
1360 		}
1361 
1362 		no->SetPointDir(TVec(x, y, 0), TVec(dx, dy, 0));
1363 
1364 		for (int j = 0; j < 2; j++)
1365 		{
1366 			no->children[j] = children[j];
1367 			no->bbox[j][0] = bbox[j][BOXLEFT];
1368 			no->bbox[j][1] = bbox[j][BOXBOTTOM];
1369 			no->bbox[j][2] = -32768.0;
1370 			no->bbox[j][3] = bbox[j][BOXRIGHT];
1371 			no->bbox[j][4] = bbox[j][BOXTOP];
1372 			no->bbox[j][5] = 32768.0;
1373 		}
1374 	}
1375 	delete Strm;
1376 	Strm = NULL;
1377 	unguard;
1378 }
1379 
1380 //==========================================================================
1381 //
1382 //  VLevel::LoadPVS
1383 //
1384 //==========================================================================
1385 
LoadPVS(int Lump)1386 void VLevel::LoadPVS(int Lump)
1387 {
1388 	guard(VLevel::LoadPVS);
1389 	if (W_LumpName(Lump) != NAME_gl_pvs || W_LumpLength(Lump) == 0)
1390 	{
1391 		GCon->Logf(NAME_Dev, "Empty or missing PVS lump");
1392 		VisData = NULL;
1393 		NoVis = new vuint8[(NumSubsectors + 7) / 8];
1394 		memset(NoVis, 0xff, (NumSubsectors + 7) / 8);
1395 	}
1396 	else
1397 	{
1398 		VisData = new byte[W_LumpLength(Lump)];
1399 		VStream* Strm = W_CreateLumpReaderNum(Lump);
1400 		Strm->Serialise(VisData, W_LumpLength(Lump));
1401 		delete Strm;
1402 		Strm = NULL;
1403 	}
1404 	unguard;
1405 }
1406 
1407 //==========================================================================
1408 //
1409 //  VLevel::LoadCompressedGLNodes
1410 //
1411 //==========================================================================
1412 
LoadCompressedGLNodes(int Lump)1413 void VLevel::LoadCompressedGLNodes(int Lump)
1414 {
1415 	guard(VLevel::LoadCompressedGLNodes);
1416 	VStream* BaseStrm = W_CreateLumpReaderNum(Lump);
1417 	//	Skip header.
1418 	BaseStrm->Seek(4);
1419 	//	Create reader stream for the zipped data.
1420 	vuint8* TmpData = new vuint8[BaseStrm->TotalSize() - 4];
1421 	BaseStrm->Serialise(TmpData, BaseStrm->TotalSize() - 4);
1422 	VStream* DataStrm = new VMemoryStream(TmpData, BaseStrm->TotalSize() - 4);
1423 	delete[] TmpData;
1424 	TmpData = NULL;
1425 	delete BaseStrm;
1426 	BaseStrm = NULL;
1427 	VStream* Strm = new VZipStreamReader(DataStrm);
1428 
1429 	//	Read extra vertex data
1430 	guard(Vertexes);
1431 	vuint32 OrgVerts;
1432 	vuint32 NewVerts;
1433 	*Strm << OrgVerts << NewVerts;
1434 
1435 	if (OrgVerts + NewVerts != (vuint32)NumVertexes)
1436 	{
1437 		vertex_t* OldVerts = Vertexes;
1438 		NumVertexes = OrgVerts + NewVerts;
1439 		Vertexes = new vertex_t[NumVertexes];
1440 		memcpy(Vertexes, OldVerts, OrgVerts * sizeof(vertex_t));
1441 		//	Fix up vertex pointers in linedefs
1442 		for (int i = 0; i < NumLines; i++)
1443 		{
1444 			line_t& L = Lines[i];
1445 			int v1 = L.v1 - OldVerts;
1446 			int v2 = L.v2 - OldVerts;
1447 			L.v1 = &Vertexes[v1];
1448 			L.v2 = &Vertexes[v2];
1449 		}
1450 		delete[] OldVerts;
1451 		OldVerts = NULL;
1452 	}
1453 
1454 	vertex_t* DstVert = Vertexes + OrgVerts;
1455 	for (vuint32 i = 0; i < NewVerts; i++, DstVert++)
1456 	{
1457 		vint32 x, y;
1458 		*Strm << x << y;
1459 		*DstVert = TVec(x / 65536.0, y / 65536.0, 0);
1460 	}
1461 	unguard;
1462 
1463 	//	Load subsectors
1464 	guard(Subsectors);
1465 	NumSubsectors = Streamer<vuint32>(*Strm);
1466 	Subsectors = new subsector_t[NumSubsectors];
1467 	memset(Subsectors, 0, sizeof(subsector_t) * NumSubsectors);
1468 	subsector_t* ss = Subsectors;
1469 	int FirstSeg = 0;
1470 	for (int i = 0; i < NumSubsectors; i++, ss++)
1471 	{
1472 		vuint32 NumSubSegs;
1473 		*Strm << NumSubSegs;
1474 		ss->numlines = NumSubSegs;
1475 		ss->firstline = FirstSeg;
1476 		FirstSeg += NumSubSegs;
1477 	}
1478 	unguard;
1479 
1480 	//	Load segs
1481 	guard(Segs);
1482 	NumSegs = Streamer<vuint32>(*Strm);
1483 	Segs = new seg_t[NumSegs];
1484 	memset(Segs, 0, sizeof(seg_t) * NumSegs);
1485 	seg_t* li = Segs;
1486 	for (int i = 0; i < NumSegs; i++, li++)
1487 	{
1488 		vuint32 v1;
1489 		vuint32 partner;
1490 		vuint16 linedef;
1491 		vuint8 side;
1492 
1493 		*Strm << v1 << partner << linedef << side;
1494 
1495 		if (v1 >= (vuint32)NumVertexes)
1496 		{
1497 			Host_Error("Bad vertex index %d", v1);
1498 		}
1499 		li->v1 = &Vertexes[v1];
1500 
1501 		if (linedef != 0xffff)
1502 		{
1503 			if (linedef >= NumLines)
1504 			{
1505 				Host_Error("Bad linedef index %d", linedef);
1506 			}
1507 			if (side > 1)
1508 			{
1509 				Host_Error("Bad seg side %d", side);
1510 			}
1511 			line_t* ldef = &Lines[linedef];
1512 			li->linedef = ldef;
1513 			li->sidedef = &Sides[ldef->sidenum[side]];
1514 			li->frontsector = Sides[ldef->sidenum[side]].Sector;
1515 
1516 			if (ldef->flags & ML_TWOSIDED)
1517 			{
1518 				li->backsector = Sides[ldef->sidenum[side ^ 1]].Sector;
1519 			}
1520 
1521 			if (side)
1522 			{
1523 				check(li);
1524 				check(li->v1);
1525 				check(ldef->v2);
1526 				li->offset = Length(*li->v1 - *ldef->v2);
1527 			}
1528 			else
1529 			{
1530 				check(li);
1531 				check(li->v1);
1532 				check(ldef->v1);
1533 				li->offset = Length(*li->v1 - *ldef->v1);
1534 			}
1535 			li->side = side;
1536 		}
1537 	}
1538 	unguard;
1539 
1540 	//	Load nodes.
1541 	guard(Nodes);
1542 	NumNodes = Streamer<vuint32>(*Strm);
1543 	Nodes = new node_t[NumNodes];
1544 	memset(Nodes, 0, sizeof(node_t) * NumNodes);
1545 	node_t* no = Nodes;
1546 	for (int i = 0; i < NumNodes; i++, no++)
1547 	{
1548 		vint16 x, y, dx, dy;
1549 		vint16 bbox[2][4];
1550 		vuint32 children[2];
1551 		*Strm << x << y << dx << dy
1552 			<< bbox[0][0] << bbox[0][1] << bbox[0][2] << bbox[0][3]
1553 			<< bbox[1][0] << bbox[1][1] << bbox[1][2] << bbox[1][3]
1554 			<< children[0] << children[1];
1555 
1556 		no->SetPointDir(TVec(x, y, 0), TVec(dx, dy, 0));
1557 
1558 		for (int j = 0; j < 2; j++)
1559 		{
1560 			no->children[j] = children[j];
1561 			no->bbox[j][0] = bbox[j][BOXLEFT];
1562 			no->bbox[j][1] = bbox[j][BOXBOTTOM];
1563 			no->bbox[j][2] = -32768.0;
1564 			no->bbox[j][3] = bbox[j][BOXRIGHT];
1565 			no->bbox[j][4] = bbox[j][BOXTOP];
1566 			no->bbox[j][5] = 32768.0;
1567 		}
1568 	}
1569 	unguard;
1570 
1571 	//	Set v2 of the segs.
1572 	guard(Set up seg v2);
1573 	subsector_t* Sub = Subsectors;
1574 	for (int i = 0; i < NumSubsectors; i++, Sub++)
1575 	{
1576 		seg_t* Seg = Segs + Sub->firstline;
1577 		for (int j = 0; j < Sub->numlines - 1; j++, Seg++)
1578 		{
1579 			Seg->v2 = Seg[1].v1;
1580 		}
1581 		Seg->v2 = Segs[Sub->firstline].v1;
1582 	}
1583 	unguard;
1584 
1585 	guard(Calc segs);
1586 	seg_t* li = Segs;
1587 	for (int i = 0; i < NumSegs; i++, li++)
1588 	{
1589 		//	Calc seg's plane params
1590 		li->length = Length(*li->v2 - *li->v1);
1591 		CalcSeg(li);
1592 	}
1593 	unguard;
1594 
1595 	guard(Calc subsectors);
1596 	subsector_t* ss = Subsectors;
1597 	for (int i = 0; i < NumSubsectors; i++, ss++)
1598 	{
1599 		// look up sector number for each subsector
1600 		seg_t* seg = &Segs[ss->firstline];
1601 		for (int j = 0; j < ss->numlines; j++)
1602 		{
1603 			if (seg[j].linedef)
1604 			{
1605 				ss->sector = seg[j].sidedef->Sector;
1606 				ss->seclink = ss->sector->subsectors;
1607 				ss->sector->subsectors = ss;
1608 				break;
1609 			}
1610 		}
1611 		if (!ss->sector)
1612 			Host_Error("Subsector %d without sector", i);
1613 	}
1614 	unguard;
1615 
1616 	//	Create dummy VIS data.
1617 	VisData = NULL;
1618 	NoVis = new vuint8[(NumSubsectors + 7) / 8];
1619 	memset(NoVis, 0xff, (NumSubsectors + 7) / 8);
1620 
1621 	delete Strm;
1622 	Strm = NULL;
1623 	delete DataStrm;
1624 	DataStrm = NULL;
1625 	unguard;
1626 }
1627 
1628 //==========================================================================
1629 //
1630 //  VLevel::LoadBlockMap
1631 //
1632 //==========================================================================
1633 
LoadBlockMap(int Lump)1634 void VLevel::LoadBlockMap(int Lump)
1635 {
1636 	guard(VLevel::LoadBlockMap);
1637 	VStream* Strm = NULL;
1638 	if (Lump >= 0 && !build_blockmap)
1639 	{
1640 		Strm = W_CreateLumpReaderNum(Lump);
1641 	}
1642 
1643 	if (!Strm || Strm->TotalSize() == 0 || Strm->TotalSize() / 2 >= 0x10000)
1644 	{
1645 		GCon->Logf("Creating BLOCKMAP");
1646 		CreateBlockMap();
1647 	}
1648 	else
1649 	{
1650 		// killough 3/1/98: Expand wad blockmap into larger internal one,
1651 		// by treating all offsets except -1 as unsigned and zero-extending
1652 		// them. This potentially doubles the size of blockmaps allowed,
1653 		// because Doom originally considered the offsets as always signed.
1654 
1655 		//	Allocate memory for blockmap.
1656 		int Count = Strm->TotalSize() / 2;
1657 		BlockMapLump = new vint32[Count];
1658 
1659 		//	Read data.
1660 		BlockMapLump[0] = Streamer<vint16>(*Strm);
1661 		BlockMapLump[1] = Streamer<vint16>(*Strm);
1662 		BlockMapLump[2] = Streamer<vuint16>(*Strm);
1663 		BlockMapLump[3] = Streamer<vuint16>(*Strm);
1664 		for (int i = 4; i < Count; i++)
1665 		{
1666 			vint16 Tmp;
1667 			*Strm << Tmp;
1668 			BlockMapLump[i] = Tmp == -1 ? -1 : (vuint16)Tmp & 0xffff;
1669 		}
1670 	}
1671 
1672 	if (Strm)
1673 	{
1674 		delete Strm;
1675 		Strm = NULL;
1676 	}
1677 
1678 	//	Read blockmap origin and size.
1679 	BlockMapOrgX = BlockMapLump[0];
1680 	BlockMapOrgY = BlockMapLump[1];
1681 	BlockMapWidth = BlockMapLump[2];
1682 	BlockMapHeight = BlockMapLump[3];
1683 	BlockMap = BlockMapLump + 4;
1684 
1685 	//	Clear out mobj chains.
1686 	int Count = BlockMapWidth * BlockMapHeight;
1687 	BlockLinks = new VEntity*[Count];
1688 	memset(BlockLinks, 0, sizeof(VEntity*) * Count);
1689 	unguard;
1690 }
1691 
1692 //==========================================================================
1693 //
1694 //  VLevel::CreateBlockMap
1695 //
1696 //==========================================================================
1697 
CreateBlockMap()1698 void VLevel::CreateBlockMap()
1699 {
1700 	guard(VLevel::CreateBlockMap);
1701 	//	Determine bounds of the map.
1702 	float MinX = Vertexes[0].x;
1703 	float MaxX = MinX;
1704 	float MinY = Vertexes[0].y;
1705 	float MaxY = MinY;
1706 	for (int i = 0; i < NumVertexes; i++)
1707 	{
1708 		if (MinX > Vertexes[i].x)
1709 		{
1710 			MinX = Vertexes[i].x;
1711 		}
1712 		if (MaxX < Vertexes[i].x)
1713 		{
1714 			MaxX = Vertexes[i].x;
1715 		}
1716 		if (MinY > Vertexes[i].y)
1717 		{
1718 			MinY = Vertexes[i].y;
1719 		}
1720 		if (MaxY < Vertexes[i].y)
1721 		{
1722 			MaxY = Vertexes[i].y;
1723 		}
1724 	}
1725 
1726 	//	They should be integers, but just in case round them.
1727 	MinX = floor(MinX);
1728 	MinY = floor(MinY);
1729 	MaxX = ceil(MaxX);
1730 	MaxY = ceil(MaxY);
1731 
1732 	int Width = MapBlock(MaxX - MinX) + 1;
1733 	int Height = MapBlock(MaxY - MinY) + 1;
1734 
1735 	//	Add all lines to their corresponding blocks
1736 	TArray<vuint16>* BlockLines = new TArray<vuint16>[Width * Height];
1737 	for (int i = 0; i < NumLines; i++)
1738 	{
1739 		//	Determine starting and ending blocks.
1740 		line_t& Line = Lines[i];
1741 		int X1 = MapBlock(Line.v1->x - MinX);
1742 		int Y1 = MapBlock(Line.v1->y - MinY);
1743 		int X2 = MapBlock(Line.v2->x - MinX);
1744 		int Y2 = MapBlock(Line.v2->y - MinY);
1745 
1746 		if (X1 > X2)
1747 		{
1748 			int Tmp = X2;
1749 			X2 = X1;
1750 			X1 = Tmp;
1751 		}
1752 		if (Y1 > Y2)
1753 		{
1754 			int Tmp = Y2;
1755 			Y2 = Y1;
1756 			Y1 = Tmp;
1757 		}
1758 
1759 		if (X1 == X2 && Y1 == Y2)
1760 		{
1761 			//	Line is inside a single block.
1762 			BlockLines[X1 + Y1 * Width].Append(i);
1763 		}
1764 		else if (Y1 == Y2)
1765 		{
1766 			//	Horisontal line of blocks.
1767 			for (int x = X1; x <= X2; x++)
1768 			{
1769 				BlockLines[x + Y1 * Width].Append(i);
1770 			}
1771 		}
1772 		else if (X1 == X2)
1773 		{
1774 			//	Vertical line of blocks.
1775 			for (int y = Y1; y <= Y2; y++)
1776 			{
1777 				BlockLines[X1 + y * Width].Append(i);
1778 			}
1779 		}
1780 		else
1781 		{
1782 			//	Diagonal line.
1783 			for (int x = X1; x <= X2; x++)
1784 			{
1785 				for (int y = Y1; y <= Y2; y++)
1786 				{
1787 					//	Check if line crosses the block
1788 					if (Line.slopetype == ST_POSITIVE)
1789 					{
1790 						int p1 = Line.PointOnSide(TVec(MinX + x * 128,
1791 							MinY + (y + 1) * 128, 0));
1792 						int p2 = Line.PointOnSide(TVec(MinX + (x + 1) * 128,
1793 							MinY + y * 128, 0));
1794 						if (p1 == p2)
1795 							continue;
1796 					}
1797 					else
1798 					{
1799 						int p1 = Line.PointOnSide(TVec(MinX + x * 128,
1800 							MinY + y * 128, 0));
1801 						int p2 = Line.PointOnSide(TVec(MinX + (x + 1) * 128,
1802 							MinY + (y + 1) * 128, 0));
1803 						if (p1 == p2)
1804 							continue;
1805 					}
1806 					BlockLines[x + y * Width].Append(i);
1807 				}
1808 			}
1809 		}
1810 	}
1811 
1812 	//	Build blockmap lump.
1813 	TArray<vint32> BMap;
1814 	BMap.SetNum(4 + Width * Height);
1815 	BMap[0] = (int)MinX;
1816 	BMap[1] = (int)MinY;
1817 	BMap[2] = Width;
1818 	BMap[3] = Height;
1819 	for (int i = 0; i < Width * Height; i++)
1820 	{
1821 		//	Write offset.
1822 		BMap[i + 4] = BMap.Num();
1823 		TArray<vuint16>& Block = BlockLines[i];
1824 		//	Add dummy start marker.
1825 		BMap.Append(0);
1826 		//	Add lines in this block.
1827 		for (int j = 0; j < Block.Num(); j++)
1828 		{
1829 			BMap.Append(Block[j]);
1830 		}
1831 		//	Add terminator marker.
1832 		BMap.Append(-1);
1833 	}
1834 
1835 	//	Copy data
1836 	BlockMapLump = new vint32[BMap.Num()];
1837 	memcpy(BlockMapLump, BMap.Ptr(), BMap.Num() * sizeof(vint32));
1838 
1839 	delete[] BlockLines;
1840 	BlockLines = NULL;
1841 	unguard;
1842 }
1843 
1844 //==========================================================================
1845 //
1846 //  VLevel::LoadReject
1847 //
1848 //==========================================================================
1849 
LoadReject(int Lump)1850 void VLevel::LoadReject(int Lump)
1851 {
1852 	guard(VLevel::LoadReject);
1853 	if (Lump < 0)
1854 	{
1855 		return;
1856 	}
1857 	VStream* Strm = W_CreateLumpReaderNum(Lump);
1858 	//	Check for empty reject lump
1859 	if (Strm->TotalSize())
1860 	{
1861 		//	Check if reject lump is required bytes long.
1862 		int NeededSize = (NumSectors * NumSectors + 7) / 8;
1863 		if (Strm->TotalSize() < NeededSize)
1864 		{
1865 			GCon->Logf("Reject data is %d bytes too short",
1866 				NeededSize - Strm->TotalSize());
1867 		}
1868 		else
1869 		{
1870 			//	Read it.
1871 			RejectMatrix = new vuint8[Strm->TotalSize()];
1872 			Strm->Serialise(RejectMatrix, Strm->TotalSize());
1873 
1874 			//	Check if it's an all-zeroes lump, in which case it's useless
1875 			// and can be discarded.
1876 			bool Blank = true;
1877 			for (int i = 0; i < NeededSize; i++)
1878 			{
1879 				if (RejectMatrix[i])
1880 				{
1881 					Blank = false;
1882 					break;
1883 				}
1884 			}
1885 			if (Blank)
1886 			{
1887 				delete[] RejectMatrix;
1888 				RejectMatrix = NULL;
1889 			}
1890 		}
1891 	}
1892 	delete Strm;
1893 	Strm = NULL;
1894 	unguard;
1895 }
1896 
1897 //==========================================================================
1898 //
1899 //  VLevel::LoadThings1
1900 //
1901 //==========================================================================
1902 
LoadThings1(int Lump)1903 void VLevel::LoadThings1(int Lump)
1904 {
1905 	guard(VLevel::LoadThings1);
1906 	NumThings = W_LumpLength(Lump) / 10;
1907 	Things = new mthing_t[NumThings];
1908 	memset(Things, 0, sizeof(mthing_t) * NumThings);
1909 
1910 	VStream* Strm = W_CreateLumpReaderNum(Lump);
1911 	mthing_t* th = Things;
1912 	for (int i = 0; i < NumThings; i++, th++)
1913 	{
1914 		vint16 x, y, angle, type, options;
1915 		*Strm << x << y << angle << type << options;
1916 
1917 		th->x = x;
1918 		th->y = y;
1919 		th->angle = angle;
1920 		th->type = type;
1921 		th->options = options & ~7;
1922 		th->SkillClassFilter = 0xffff0000;
1923 		if (options & 1)
1924 		{
1925 			th->SkillClassFilter |= 0x03;
1926 		}
1927 		if (options & 2)
1928 		{
1929 			th->SkillClassFilter |= 0x04;
1930 		}
1931 		if (options & 4)
1932 		{
1933 			th->SkillClassFilter |= 0x18;
1934 		}
1935 	}
1936 	delete Strm;
1937 	Strm = NULL;
1938 	unguard;
1939 }
1940 
1941 //==========================================================================
1942 //
1943 //  VLevel::LoadThings2
1944 //
1945 //==========================================================================
1946 
LoadThings2(int Lump)1947 void VLevel::LoadThings2(int Lump)
1948 {
1949 	guard(VLevel::LoadThings2);
1950 	NumThings = W_LumpLength(Lump) / 20;
1951 	Things = new mthing_t[NumThings];
1952 	memset(Things, 0, sizeof(mthing_t) * NumThings);
1953 
1954 	VStream* Strm = W_CreateLumpReaderNum(Lump);
1955 	mthing_t* th = Things;
1956 	for (int i = 0; i < NumThings; i++, th++)
1957 	{
1958 		vint16 tid, x, y, height, angle, type, options;
1959 		vuint8 special, arg1, arg2, arg3, arg4, arg5;
1960 		*Strm << tid << x << y << height << angle << type << options
1961 			<< special << arg1 << arg2 << arg3 << arg4 << arg5;
1962 
1963 		th->tid = tid;
1964 		th->x = x;
1965 		th->y = y;
1966 		th->height = height;
1967 		th->angle = angle;
1968 		th->type = type;
1969 		th->options = options & ~0xe7;
1970 		th->SkillClassFilter = (options & 0xe0) << 11;
1971 		if (options & 1)
1972 		{
1973 			th->SkillClassFilter |= 0x03;
1974 		}
1975 		if (options & 2)
1976 		{
1977 			th->SkillClassFilter |= 0x04;
1978 		}
1979 		if (options & 4)
1980 		{
1981 			th->SkillClassFilter |= 0x18;
1982 		}
1983 		th->special = special;
1984 		th->arg1 = arg1;
1985 		th->arg2 = arg2;
1986 		th->arg3 = arg3;
1987 		th->arg4 = arg4;
1988 		th->arg5 = arg5;
1989 	}
1990 	delete Strm;
1991 	Strm = NULL;
1992 	unguard;
1993 }
1994 
1995 //==========================================================================
1996 //
1997 //	VLevel::LoadACScripts
1998 //
1999 //==========================================================================
2000 
LoadACScripts(int Lump)2001 void VLevel::LoadACScripts(int Lump)
2002 {
2003 	guard(VLevel::LoadACScripts);
2004 	Acs = new VAcsLevel(this);
2005 
2006 	//	Load level's BEHAVIOR lump if it has one.
2007 	if (Lump >= 0)
2008 	{
2009 		Acs->LoadObject(Lump);
2010 	}
2011 
2012 	//	Load ACS helper scripts if needed (for Strife).
2013 	if (GGameInfo->AcsHelper != NAME_None)
2014 	{
2015 		Acs->LoadObject(W_GetNumForName(GGameInfo->AcsHelper,
2016 			WADNS_ACSLibrary));
2017 	}
2018 
2019 	//	Load user-specified default ACS libraries.
2020 	for (int ScLump = W_IterateNS(-1, WADNS_Global); ScLump >= 0;
2021 		ScLump = W_IterateNS(ScLump, WADNS_Global))
2022 	{
2023 		if (W_LumpName(ScLump) != NAME_loadacs)
2024 		{
2025 			continue;
2026 		}
2027 
2028 		VScriptParser* sc = new VScriptParser(*W_LumpName(ScLump),
2029 			W_CreateLumpReaderNum(ScLump));
2030 		while (!sc->AtEnd())
2031 		{
2032 			sc->ExpectName8();
2033 			int AcsLump = W_CheckNumForName(sc->Name8, WADNS_ACSLibrary);
2034 			if (AcsLump >= 0)
2035 			{
2036 				Acs->LoadObject(AcsLump);
2037 			}
2038 			else
2039 			{
2040 				GCon->Logf("No such autoloaded ACS library %s", *sc->String);
2041 			}
2042 		}
2043 		delete sc;
2044 		sc = NULL;
2045 	}
2046 	unguard;
2047 }
2048 
2049 //==========================================================================
2050 //
2051 //  VLevel::TexNumForName
2052 //
2053 //  Retrieval, get a texture or flat number for a name.
2054 //
2055 //==========================================================================
2056 
TexNumForName(const char * name,int Type,bool CMap) const2057 int VLevel::TexNumForName(const char *name, int Type, bool CMap) const
2058 {
2059 	guard(VLevel::TexNumForName);
2060 	VName Name(name, VName::AddLower8);
2061 	int i = GTextureManager.CheckNumForName(Name, Type, true, true);
2062 	if (i == -1)
2063 	{
2064 		if (CMap)
2065 		{
2066 			return 0;
2067 		}
2068 		GCon->Logf("FTNumForName: %s not found", *Name);
2069 		return GTextureManager.DefaultTexture;
2070 	}
2071 	return i;
2072 	unguard;
2073 }
2074 
2075 //==========================================================================
2076 //
2077 //  VLevel::TexNumOrColour
2078 //
2079 //==========================================================================
2080 
TexNumOrColour(const char * name,int Type,bool & GotColour,vuint32 & Col) const2081 int VLevel::TexNumOrColour(const char *name, int Type, bool& GotColour,
2082 	vuint32& Col) const
2083 {
2084 	guard(VLevel::TexNumOrColour);
2085 	VName Name(name, VName::AddLower8);
2086 	int i = GTextureManager.CheckNumForName(Name, Type, true, true);
2087 	if (i == -1)
2088 	{
2089 		char TmpName[9];
2090 		memcpy(TmpName, name, 8);
2091 		TmpName[8] = 0;
2092 		char* Stop;
2093 		Col = strtoul(TmpName, &Stop, 16);
2094 		GotColour = (*Stop == 0) && (Stop >= TmpName + 2) &&
2095 			(Stop <= TmpName + 6);
2096 		return 0;
2097 	}
2098 	GotColour = false;
2099 	return i;
2100 	unguard;
2101 }
2102 
2103 //==========================================================================
2104 //
2105 //	VLevel::LoadRogueConScript
2106 //
2107 //==========================================================================
2108 
LoadRogueConScript(VName LumpName,int ALumpNum,FRogueConSpeech * & SpeechList,int & NumSpeeches) const2109 void VLevel::LoadRogueConScript(VName LumpName, int ALumpNum,
2110 	FRogueConSpeech*& SpeechList, int& NumSpeeches) const
2111 {
2112 	guard(VLevel::LoadRogueConScript);
2113 	bool teaser = false;
2114 	//	Clear variables.
2115 	SpeechList = NULL;
2116 	NumSpeeches = 0;
2117 
2118 	int LumpNum = ALumpNum;
2119 	if (LumpNum < 0)
2120 	{
2121 		//	Check for empty name.
2122 		if (LumpName == NAME_None)
2123 		{
2124 			return;
2125 		}
2126 
2127 		//	Get lump num.
2128 		LumpNum = W_CheckNumForName(LumpName);
2129 		if (LumpNum < 0)
2130 		{
2131 			return;	//	Not here.
2132 		}
2133 	}
2134 
2135 	//	Load them.
2136 
2137 	//  First check the size of the lump, if it's 1516,
2138 	//  we are using a registered strife lump, if it's
2139 	//  1488, then it's a teaser conversation script
2140 	if (W_LumpLength(LumpNum) % 1516 != 0)
2141 	{
2142 		NumSpeeches = W_LumpLength(LumpNum) / 1488;
2143 		teaser = true;
2144 	}
2145 	else
2146 	{
2147 		NumSpeeches = W_LumpLength(LumpNum) / 1516;
2148 	}
2149 	SpeechList = new FRogueConSpeech[NumSpeeches];
2150 
2151 	VStream* Strm = W_CreateLumpReaderNum(LumpNum);
2152 	for (int i = 0; i < NumSpeeches; i++)
2153 	{
2154 		char Tmp[324];
2155 
2156 		FRogueConSpeech& S = SpeechList[i];
2157 		if (!teaser)
2158 		{
2159 			// Parse non teaser speech
2160 			*Strm << S.SpeakerID << S.DropItem << S.CheckItem1 << S.CheckItem2
2161 				<< S.CheckItem3 << S.JumpToConv;
2162 
2163 			// Parse NPC name
2164 			Strm->Serialise(Tmp, 16);
2165 			Tmp[16] = 0;
2166 			S.Name = Tmp;
2167 
2168 			// Parse sound name (if any)
2169 			Strm->Serialise(Tmp, 8);
2170 			Tmp[8] = 0;
2171 			S.Voice = VName(Tmp, VName::AddLower8);
2172 			if (S.Voice != NAME_None)
2173 			{
2174 				S.Voice = va("svox/%s", *S.Voice);
2175 			}
2176 
2177 			// Parse backdrop pics (if any)
2178 			Strm->Serialise(Tmp, 8);
2179 			Tmp[8] = 0;
2180 			S.BackPic = VName(Tmp, VName::AddLower8);
2181 
2182 			// Parse speech text
2183 			Strm->Serialise(Tmp, 320);
2184 			Tmp[320] = 0;
2185 			S.Text = Tmp;
2186 		}
2187 		else
2188 		{
2189 			// Parse teaser speech, which doesn't contain all fields
2190 			*Strm << S.SpeakerID << S.DropItem;
2191 
2192 			// Parse NPC name
2193 			Strm->Serialise(Tmp, 16);
2194 			Tmp[16] = 0;
2195 			S.Name = Tmp;
2196 
2197 			// Parse sound number (if any)
2198 			vint32 Num;
2199 			*Strm << Num;
2200 			if (Num)
2201 			{
2202 				S.Voice = va("svox/voc%d", Num);
2203 			}
2204 
2205 			// Also, teaser speeches don't have backdrop pics
2206 			S.BackPic = NAME_None;
2207 
2208 			// Parse speech text
2209 			Strm->Serialise(Tmp, 320);
2210 			Tmp[320] = 0;
2211 			S.Text = Tmp;
2212 		}
2213 
2214 		// Parse conversation options for PC
2215 		for (int j = 0; j < 5; j++)
2216 		{
2217 			FRogueConChoice& C = S.Choices[j];
2218 			*Strm << C.GiveItem << C.NeedItem1 << C.NeedItem2 << C.NeedItem3
2219 				<< C.NeedAmount1 << C.NeedAmount2 << C.NeedAmount3;
2220 			Strm->Serialise(Tmp, 32);
2221 			Tmp[32] = 0;
2222 			C.Text = Tmp;
2223 			Strm->Serialise(Tmp, 80);
2224 			Tmp[80] = 0;
2225 			C.TextOK = Tmp;
2226 			*Strm << C.Next << C.Objectives;
2227 			Strm->Serialise(Tmp, 80);
2228 			Tmp[80] = 0;
2229 			C.TextNo = Tmp;
2230 		}
2231 	}
2232 	delete Strm;
2233 	Strm = NULL;
2234 	unguard;
2235 }
2236 
2237 //==========================================================================
2238 //
2239 //  VLevel::ClearBox
2240 //
2241 //==========================================================================
2242 
ClearBox(float * box) const2243 inline void VLevel::ClearBox(float* box) const
2244 {
2245 	guardSlow(VLevel::ClearBox);
2246 	box[BOXTOP] = box[BOXRIGHT] = -99999.0;
2247 	box[BOXBOTTOM] = box[BOXLEFT] = 99999.0;
2248 	unguardSlow;
2249 }
2250 
2251 //==========================================================================
2252 //
2253 //  VLevel::AddToBox
2254 //
2255 //==========================================================================
2256 
AddToBox(float * box,float x,float y) const2257 inline void VLevel::AddToBox(float* box, float x, float y) const
2258 {
2259 	guardSlow(VLevel::AddToBox);
2260 	if (x < box[BOXLEFT])
2261 		box[BOXLEFT] = x;
2262 	else if (x > box[BOXRIGHT])
2263 		box[BOXRIGHT] = x;
2264 	if (y < box[BOXBOTTOM])
2265 		box[BOXBOTTOM] = y;
2266 	else if (y > box[BOXTOP])
2267 		box[BOXTOP] = y;
2268 	unguardSlow;
2269 }
2270 
2271 //==========================================================================
2272 //
2273 //  VLevel::GroupLines
2274 //
2275 //  Builds sector line lists and subsector sector numbers. Finds block
2276 // bounding boxes for sectors.
2277 //
2278 //==========================================================================
2279 
GroupLines() const2280 void VLevel::GroupLines() const
2281 {
2282 	guard(VLevel::GroupLines);
2283 	line_t ** linebuffer;
2284 	int i;
2285 	int total;
2286 	line_t *li;
2287 	sector_t *sector;
2288 	float bbox[4];
2289 	int block;
2290 
2291 	LinkNode(NumNodes - 1, NULL);
2292 
2293 	// count number of lines in each sector
2294 	li = Lines;
2295 	total = 0;
2296 	for (i = 0; i < NumLines; i++, li++)
2297 	{
2298 		total++;
2299 		li->frontsector->linecount++;
2300 
2301 		if (li->backsector && li->backsector != li->frontsector)
2302 		{
2303 			li->backsector->linecount++;
2304 			total++;
2305 		}
2306 	}
2307 
2308 	// build line tables for each sector
2309 	linebuffer = new line_t*[total];
2310 	sector = Sectors;
2311 	for (i = 0; i < NumSectors; i++, sector++)
2312 	{
2313 		sector->lines = linebuffer;
2314 		linebuffer += sector->linecount;
2315 	}
2316 
2317 	//	Assign lines for each sector.
2318 	int* SecLineCount = new int[NumSectors];
2319 	memset(SecLineCount, 0, sizeof(int) * NumSectors);
2320 	li = Lines;
2321 	for (i = 0; i < NumLines; i++, li++)
2322 	{
2323 		if (li->frontsector)
2324 		{
2325 			li->frontsector->lines[SecLineCount[
2326 				li->frontsector - Sectors]++] = li;
2327 		}
2328 		if (li->backsector && li->backsector != li->frontsector)
2329 		{
2330 			li->backsector->lines[SecLineCount[
2331 				li->backsector - Sectors]++] = li;
2332 		}
2333 	}
2334 
2335 	sector = Sectors;
2336 	for (i = 0; i < NumSectors; i++, sector++)
2337 	{
2338 		if (SecLineCount[i] != sector->linecount)
2339 		{
2340 			Sys_Error("GroupLines: miscounted");
2341 		}
2342 		ClearBox(bbox);
2343 		for (int j = 0; j < sector->linecount; j++)
2344 		{
2345 			li = sector->lines[j];
2346 			AddToBox(bbox, li->v1->x, li->v1->y);
2347 			AddToBox(bbox, li->v2->x, li->v2->y);
2348 		}
2349 
2350 		// set the soundorg to the middle of the bounding box
2351 		sector->soundorg = TVec((bbox[BOXRIGHT] + bbox[BOXLEFT]) / 2.0,
2352 			(bbox[BOXTOP] + bbox[BOXBOTTOM]) / 2.0, 0);
2353 
2354 		// adjust bounding box to map blocks
2355 		block = MapBlock(bbox[BOXTOP] - BlockMapOrgY + MAXRADIUS);
2356 		block = block >= BlockMapHeight ? BlockMapHeight - 1 : block;
2357 		sector->blockbox[BOXTOP] = block;
2358 
2359 		block = MapBlock(bbox[BOXBOTTOM] - BlockMapOrgY - MAXRADIUS);
2360 		block = block < 0 ? 0 : block;
2361 		sector->blockbox[BOXBOTTOM] = block;
2362 
2363 		block = MapBlock(bbox[BOXRIGHT] - BlockMapOrgX + MAXRADIUS);
2364 		block = block >= BlockMapWidth ? BlockMapWidth - 1 : block;
2365 		sector->blockbox[BOXRIGHT] = block;
2366 
2367 		block = MapBlock(bbox[BOXLEFT] - BlockMapOrgX - MAXRADIUS);
2368 		block = block < 0 ? 0 : block;
2369 		sector->blockbox[BOXLEFT] = block;
2370 	}
2371 	delete[] SecLineCount;
2372 	SecLineCount = NULL;
2373 	unguard;
2374 }
2375 
2376 //==========================================================================
2377 //
2378 //  VLevel::LinkNode
2379 //
2380 //==========================================================================
2381 
LinkNode(int BSPNum,node_t * pParent) const2382 void VLevel::LinkNode(int BSPNum, node_t* pParent) const
2383 {
2384 	guardSlow(LinkNode);
2385 	if (BSPNum & NF_SUBSECTOR)
2386 	{
2387 		int num;
2388 
2389 		if (BSPNum == -1)
2390 			num = 0;
2391 		else
2392 			num = BSPNum & (~NF_SUBSECTOR);
2393 		if (num < 0 || num >= NumSubsectors)
2394 			Host_Error("ss %i with numss = %i", num, NumSubsectors);
2395 		Subsectors[num].parent = pParent;
2396 	}
2397 	else
2398 	{
2399 		if (BSPNum < 0 || BSPNum >= NumNodes)
2400 			Host_Error("bsp %i with numnodes = %i", NumNodes, NumNodes);
2401 		node_t* bsp = &Nodes[BSPNum];
2402 		bsp->parent = pParent;
2403 
2404 		LinkNode(bsp->children[0], bsp);
2405 		LinkNode(bsp->children[1], bsp);
2406 	}
2407 	unguardSlow;
2408 }
2409 
2410 //==========================================================================
2411 //
2412 //  VLevel::CreateRepBase
2413 //
2414 //==========================================================================
2415 
CreateRepBase()2416 void VLevel::CreateRepBase()
2417 {
2418 	guard(VLevel::CreateRepBase);
2419 	BaseLines = new rep_line_t[NumLines];
2420 	for (int i = 0; i < NumLines; i++)
2421 	{
2422 		line_t& L = Lines[i];
2423 		rep_line_t& B = BaseLines[i];
2424 		B.alpha = L.alpha;
2425 	}
2426 
2427 	BaseSides = new rep_side_t[NumSides];
2428 	for (int i = 0; i < NumSides; i++)
2429 	{
2430 		side_t& S = Sides[i];
2431 		rep_side_t& B = BaseSides[i];
2432 		B.TopTextureOffset = S.TopTextureOffset;
2433 		B.BotTextureOffset = S.BotTextureOffset;
2434 		B.MidTextureOffset = S.MidTextureOffset;
2435 		B.TopRowOffset = S.TopRowOffset;
2436 		B.BotRowOffset = S.BotRowOffset;
2437 		B.MidRowOffset = S.MidRowOffset;
2438 		B.TopTexture = S.TopTexture;
2439 		B.BottomTexture = S.BottomTexture;
2440 		B.MidTexture = S.MidTexture;
2441 		B.Flags = S.Flags;
2442 		B.Light = S.Light;
2443 	}
2444 
2445 	BaseSectors = new rep_sector_t[NumSectors];
2446 	for (int i = 0; i < NumSectors; i++)
2447 	{
2448 		sector_t& S = Sectors[i];
2449 		rep_sector_t& B = BaseSectors[i];
2450 		B.floor_pic = S.floor.pic;
2451 		B.floor_dist = S.floor.dist;
2452 		B.floor_xoffs = S.floor.xoffs;
2453 		B.floor_yoffs = S.floor.yoffs;
2454 		B.floor_XScale = S.floor.XScale;
2455 		B.floor_YScale = S.floor.YScale;
2456 		B.floor_Angle = S.floor.Angle;
2457 		B.floor_BaseAngle = S.floor.BaseAngle;
2458 		B.floor_BaseYOffs = S.floor.BaseYOffs;
2459 		B.floor_SkyBox = NULL;
2460 		B.floor_MirrorAlpha = S.floor.MirrorAlpha;
2461 		B.ceil_pic = S.ceiling.pic;
2462 		B.ceil_dist = S.ceiling.dist;
2463 		B.ceil_xoffs = S.ceiling.xoffs;
2464 		B.ceil_yoffs = S.ceiling.yoffs;
2465 		B.ceil_XScale = S.ceiling.XScale;
2466 		B.ceil_YScale = S.ceiling.YScale;
2467 		B.ceil_Angle = S.ceiling.Angle;
2468 		B.ceil_BaseAngle = S.ceiling.BaseAngle;
2469 		B.ceil_BaseYOffs = S.ceiling.BaseYOffs;
2470 		B.ceil_SkyBox = NULL;
2471 		B.ceil_MirrorAlpha = S.ceiling.MirrorAlpha;
2472 		B.lightlevel = S.params.lightlevel;
2473 		B.Fade = S.params.Fade;
2474 		B.Sky = S.Sky;
2475 	}
2476 
2477 	BasePolyObjs = new rep_polyobj_t[NumPolyObjs];
2478 	for (int i = 0; i < NumPolyObjs; i++)
2479 	{
2480 		polyobj_t& P = PolyObjs[i];
2481 		rep_polyobj_t& B = BasePolyObjs[i];
2482 		B.startSpot = P.startSpot;
2483 		B.angle = P.angle;
2484 	}
2485 	unguard;
2486 }
2487 
2488 //==========================================================================
2489 //
2490 //  VLevel::HashSectors
2491 //
2492 //==========================================================================
2493 
HashSectors()2494 void VLevel::HashSectors()
2495 {
2496 	guard(VLevel::HashSectors);
2497 	//	Clear hash.
2498 	for (int i = 0; i < NumSectors; i++)
2499 	{
2500 		Sectors[i].HashFirst = -1;
2501 	}
2502 	//	Create hash. Process sectors in backward order so that they get
2503 	// processed in original order.
2504 	for (int i = NumSectors - 1; i >= 0; i--)
2505 	{
2506 		vuint32 HashIndex = (vuint32)Sectors[i].tag % (vuint32)NumSectors;
2507 		Sectors[i].HashNext = Sectors[HashIndex].HashFirst;
2508 		Sectors[HashIndex].HashFirst = i;
2509 	}
2510 	unguard;
2511 }
2512 
2513 //==========================================================================
2514 //
2515 //  VLevel::HashLines
2516 //
2517 //==========================================================================
2518 
HashLines()2519 void VLevel::HashLines()
2520 {
2521 	guard(VLevel::HashLines);
2522 	//	Clear hash.
2523 	for (int i = 0; i < NumLines; i++)
2524 	{
2525 		Lines[i].HashFirst = -1;
2526 	}
2527 	//	Create hash. Process lines in backward order so that they get
2528 	// processed in original order.
2529 	for (int i = NumLines - 1; i >= 0; i--)
2530 	{
2531 		vuint32 HashIndex = (vuint32)Lines[i].LineTag % (vuint32)NumLines;
2532 		Lines[i].HashNext = Lines[HashIndex].HashFirst;
2533 		Lines[HashIndex].HashFirst = i;
2534 	}
2535 	unguard;
2536 }
2537 
2538 //==========================================================================
2539 //
2540 //	VLevel::FloodZones
2541 //
2542 //==========================================================================
2543 
FloodZones()2544 void VLevel::FloodZones()
2545 {
2546 	guard(VLevel::FloodZones);
2547 	for (int i = 0; i < NumSectors; i++)
2548 	{
2549 		if (Sectors[i].Zone == -1)
2550 		{
2551 			FloodZone(&Sectors[i], NumZones);
2552 			NumZones++;
2553 		}
2554 	}
2555 
2556 	Zones = new vint32[NumZones];
2557 	for (int i = 0; i < NumZones; i++)
2558 	{
2559 		Zones[i] = 0;
2560 	}
2561 	unguard;
2562 }
2563 
2564 //==========================================================================
2565 //
2566 //	VLevel::FloodZone
2567 //
2568 //==========================================================================
2569 
FloodZone(sector_t * Sec,int Zone)2570 void VLevel::FloodZone(sector_t* Sec, int Zone)
2571 {
2572 	guard(VLevel::FloodZone);
2573 	Sec->Zone = Zone;
2574 	for (int i = 0; i < Sec->linecount; i++)
2575 	{
2576 		line_t* Line = Sec->lines[i];
2577 		if (Line->flags & ML_ZONEBOUNDARY)
2578 		{
2579 			continue;
2580 		}
2581 		if (Line->frontsector && Line->frontsector->Zone == -1)
2582 		{
2583 			FloodZone(Line->frontsector, Zone);
2584 		}
2585 		if (Line->backsector && Line->backsector->Zone == -1)
2586 		{
2587 			FloodZone(Line->backsector, Zone);
2588 		}
2589 	}
2590 	unguard;
2591 }
2592