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