1 
2 //**************************************************************************
3 //**
4 //** TEMPLATE.C
5 //**
6 //**************************************************************************
7 
8 // HEADER FILES ------------------------------------------------------------
9 
10 #include "p_local.h"
11 #include "m_swap.h"
12 #include "w_wad.h"
13 #include "templates.h"
14 #include "r_sky.h"
15 #include "r_defs.h"
16 #include "p_setup.h"
17 #include "g_level.h"
18 #include "r_data/colormaps.h"
19 #include "gi.h"
20 
21 // MACROS ------------------------------------------------------------------
22 
23 //#define SHADE2LIGHT(s) (160-2*(s))
24 #define SHADE2LIGHT(s) (255-2*s)
25 
26 // TYPES -------------------------------------------------------------------
27 
28 //ceilingstat/floorstat:
29 //   bit 0: 1 = parallaxing, 0 = not                                 "P"
30 //   bit 1: 1 = groudraw, 0 = not
31 //   bit 2: 1 = swap x&y, 0 = not                                    "F"
32 //   bit 3: 1 = double smooshiness                                   "E"
33 //   bit 4: 1 = x-flip                                               "F"
34 //   bit 5: 1 = y-flip                                               "F"
35 //   bit 6: 1 = Align texture to first wall of sector                "R"
36 //   bits 7-8:                                                       "T"
37 //          00 = normal floors
38 //          01 = masked floors
39 //          10 = transluscent masked floors
40 //          11 = reverse transluscent masked floors
41 //   bits 9-15: reserved
42 
43 	//40 bytes
44 struct sectortype
45 {
46 	SWORD wallptr, wallnum;
47 	SDWORD ceilingz, floorz;
48 	SWORD ceilingstat, floorstat;
49 	SWORD ceilingpicnum, ceilingheinum;
50 	SBYTE ceilingshade;
51 	BYTE ceilingpal, ceilingxpanning, ceilingypanning;
52 	SWORD floorpicnum, floorheinum;
53 	SBYTE floorshade;
54 	BYTE floorpal, floorxpanning, floorypanning;
55 	BYTE visibility, filler;
56 	SWORD lotag, hitag, extra;
57 };
58 
59 //cstat:
60 //   bit 0: 1 = Blocking wall (use with clipmove, getzrange)         "B"
61 //   bit 1: 1 = bottoms of invisible walls swapped, 0 = not          "2"
62 //   bit 2: 1 = align picture on bottom (for doors), 0 = top         "O"
63 //   bit 3: 1 = x-flipped, 0 = normal                                "F"
64 //   bit 4: 1 = masking wall, 0 = not                                "M"
65 //   bit 5: 1 = 1-way wall, 0 = not                                  "1"
66 //   bit 6: 1 = Blocking wall (use with hitscan / cliptype 1)        "H"
67 //   bit 7: 1 = Transluscence, 0 = not                               "T"
68 //   bit 8: 1 = y-flipped, 0 = normal                                "F"
69 //   bit 9: 1 = Transluscence reversing, 0 = normal                  "T"
70 //   bits 10-15: reserved
71 
72 	//32 bytes
73 struct walltype
74 {
75 	SDWORD x, y;
76 	SWORD point2, nextwall, nextsector, cstat;
77 	SWORD picnum, overpicnum;
78 	SBYTE shade;
79 	BYTE pal, xrepeat, yrepeat, xpanning, ypanning;
80 	SWORD lotag, hitag, extra;
81 };
82 
83 //cstat:
84 //   bit 0: 1 = Blocking sprite (use with clipmove, getzrange)       "B"
85 //   bit 1: 1 = transluscence, 0 = normal                            "T"
86 //   bit 2: 1 = x-flipped, 0 = normal                                "F"
87 //   bit 3: 1 = y-flipped, 0 = normal                                "F"
88 //   bits 5-4: 00 = FACE sprite (default)                            "R"
89 //             01 = WALL sprite (like masked walls)
90 //             10 = FLOOR sprite (parallel to ceilings&floors)
91 //   bit 6: 1 = 1-sided sprite, 0 = normal                           "1"
92 //   bit 7: 1 = Real centered centering, 0 = foot center             "C"
93 //   bit 8: 1 = Blocking sprite (use with hitscan / cliptype 1)      "H"
94 //   bit 9: 1 = Transluscence reversing, 0 = normal                  "T"
95 //   bits 10-14: reserved
96 //   bit 15: 1 = Invisible sprite, 0 = not invisible
97 
98 	//44 bytes
99 struct spritetype
100 {
101 	SDWORD x, y, z;
102 	SWORD cstat, picnum;
103 	SBYTE shade;
104 	BYTE pal, clipdist, filler;
105 	BYTE xrepeat, yrepeat;
106 	SBYTE xoffset, yoffset;
107 	SWORD sectnum, statnum;
108 	SWORD ang, owner, xvel, yvel, zvel;
109 	SWORD lotag, hitag, extra;
110 };
111 
112 // I used to have all the Xobjects mapped out. Not anymore.
113 // (Thanks for the great firmware, Seagate!)
114 struct Xsprite
115 {
116 	BYTE NotReallyPadding[16];
117 	WORD Data1;
118 	WORD Data2;
119 	WORD Data3;
120 	WORD ThisIsntPaddingEither;
121 	DWORD NorThis:2;
122 	DWORD Data4:16;
123 	DWORD WhatIsThisIDontEven:14;
124 	BYTE ThisNeedsToBe56Bytes[28];
125 };
126 
127 struct SlopeWork
128 {
129 	walltype *wal;
130 	walltype *wal2;
131 	long dx, dy, i, x[3], y[3], z[3];
132 	long heinum;
133 };
134 
135 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
136 
137 void P_AdjustLine (line_t *line);
138 
139 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
140 
141 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
142 
143 static bool P_LoadBloodMap (BYTE *data, size_t len, FMapThing **sprites, int *numsprites);
144 static void LoadSectors (sectortype *bsectors);
145 static void LoadWalls (walltype *walls, int numwalls, sectortype *bsectors);
146 static int LoadSprites (spritetype *sprites, Xsprite *xsprites, int numsprites, sectortype *bsectors, FMapThing *mapthings);
147 static vertex_t *FindVertex (fixed_t x, fixed_t y);
148 static void CreateStartSpot (fixed_t *pos, FMapThing *start);
149 static void CalcPlane (SlopeWork &slope, secplane_t &plane);
150 static void Decrypt (void *to, const void *from, int len, int key);
151 
152 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
153 
154 // PUBLIC DATA DEFINITIONS -------------------------------------------------
155 
156 // PRIVATE DATA DEFINITIONS ------------------------------------------------
157 
158 // CODE --------------------------------------------------------------------
159 
P_IsBuildMap(MapData * map)160 bool P_IsBuildMap(MapData *map)
161 {
162 	DWORD len = map->Size(ML_LABEL);
163 	if (len < 4)
164 	{
165 		return false;
166 	}
167 	BYTE *data = new BYTE[len];
168 
169 	map->Seek(ML_LABEL);
170 	map->Read(ML_LABEL, data);
171 
172 	// Check for a Blood map.
173 	if (*(DWORD *)data == MAKE_ID('B','L','M','\x1a'))
174 	{
175 		delete[] data;
176 		return true;
177 	}
178 
179 	const int numsec = LittleShort(*(WORD *)(data + 20));
180 	int numwalls;
181 
182 	if (len < 26 + numsec*sizeof(sectortype) ||
183 		(numwalls = LittleShort(*(WORD *)(data + 22 + numsec*sizeof(sectortype))),
184 			len < 24 + numsec*sizeof(sectortype) + numwalls*sizeof(walltype)) ||
185 		LittleLong(*(DWORD *)data) != 7 ||
186 		LittleShort(*(WORD *)(data + 16)) >= 2048)
187 	{ // Can't possibly be a version 7 BUILD map
188 		delete[] data;
189 		return false;
190 	}
191 	delete[] data;
192 	return true;
193 }
194 
195 //==========================================================================
196 //
197 // P_LoadBuildMap
198 //
199 //==========================================================================
200 
P_LoadBuildMap(BYTE * data,size_t len,FMapThing ** sprites,int * numspr)201 bool P_LoadBuildMap (BYTE *data, size_t len, FMapThing **sprites, int *numspr)
202 {
203 	if (len < 26)
204 	{
205 		return false;
206 	}
207 
208 	// Check for a Blood map.
209 	if (*(DWORD *)data == MAKE_ID('B','L','M','\x1a'))
210 	{
211 		return P_LoadBloodMap (data, len, sprites, numspr);
212 	}
213 
214 	const int numsec = LittleShort(*(WORD *)(data + 20));
215 	int numwalls;
216 	int numsprites;
217 
218 	if (len < 26 + numsec*sizeof(sectortype) ||
219 		(numwalls = LittleShort(*(WORD *)(data + 22 + numsec*sizeof(sectortype))),
220 			len < 24 + numsec*sizeof(sectortype) + numwalls*sizeof(walltype)) ||
221 		LittleLong(*(DWORD *)data) != 7 ||
222 		LittleShort(*(WORD *)(data + 16)) >= 2048)
223 	{ // Can't possibly be a version 7 BUILD map
224 		return false;
225 	}
226 
227 	numsectors = numsec;
228 	LoadSectors ((sectortype *)(data + 22));
229 	LoadWalls ((walltype *)(data + 24 + numsectors*sizeof(sectortype)), numwalls,
230 		(sectortype *)(data + 22));
231 
232 	numsprites = *(WORD *)(data + 24 + numsectors*sizeof(sectortype) + numwalls*sizeof(walltype));
233 	*sprites = new FMapThing[numsprites + 1];
234 	CreateStartSpot ((fixed_t *)(data + 4), *sprites);
235 	*numspr = 1 + LoadSprites ((spritetype *)(data + 26 + numsectors*sizeof(sectortype) + numwalls*sizeof(walltype)),
236 		NULL, numsprites, (sectortype *)(data + 22), *sprites + 1);
237 
238 	return true;
239 }
240 
241 //==========================================================================
242 //
243 // P_LoadBloodMap
244 //
245 //==========================================================================
246 
P_LoadBloodMap(BYTE * data,size_t len,FMapThing ** mapthings,int * numspr)247 static bool P_LoadBloodMap (BYTE *data, size_t len, FMapThing **mapthings, int *numspr)
248 {
249 	BYTE infoBlock[37];
250 	int mapver = data[5];
251 	DWORD matt;
252 	int numRevisions, numWalls, numsprites, skyLen, visibility, parallaxType;
253 	int i;
254 	int k;
255 
256 	if (mapver != 6 && mapver != 7)
257 	{
258 		return false;
259 	}
260 
261 	matt = *(DWORD *)(data + 28);
262 	if (matt != 0 &&
263 		matt != MAKE_ID('M','a','t','t') &&
264 		matt != MAKE_ID('t','t','a','M'))
265 	{
266 		Decrypt (infoBlock, data + 6, 37, 0x7474614d);
267 	}
268 	else
269 	{
270 		memcpy (infoBlock, data + 6, 37);
271 	}
272 	skyLen = 2 << LittleShort(*(WORD *)(infoBlock + 16));
273 	visibility = LittleLong(*(DWORD *)(infoBlock + 18));
274 	parallaxType = infoBlock[26];
275 	numRevisions = LittleLong(*(DWORD *)(infoBlock + 27));
276 	numsectors = LittleShort(*(WORD *)(infoBlock + 31));
277 	numWalls = LittleShort(*(WORD *)(infoBlock + 33));
278 	numsprites = LittleShort(*(WORD *)(infoBlock + 35));
279 	Printf("Visibility: %d\n", visibility);
280 
281 	if (mapver == 7)
282 	{
283 		// Version 7 has some extra stuff after the info block. This
284 		// includes a copyright, and I have no idea what the rest of
285 		// it is.
286 		data += 171;
287 	}
288 	else
289 	{
290 		data += 43;
291 	}
292 
293 	// Skip the sky info.
294 	data += skyLen;
295 
296 	sectortype *bsec = new sectortype[numsectors];
297 	walltype *bwal = new walltype[numWalls];
298 	spritetype *bspr = new spritetype[numsprites];
299 	Xsprite *xspr = new Xsprite[numsprites];
300 
301 	// Read sectors
302 	k = numRevisions * sizeof(sectortype);
303 	for (i = 0; i < numsectors; ++i)
304 	{
305 		if (mapver == 7)
306 		{
307 			Decrypt (&bsec[i], data, sizeof(sectortype), k);
308 		}
309 		else
310 		{
311 			memcpy (&bsec[i], data, sizeof(sectortype));
312 		}
313 		data += sizeof(sectortype);
314 		if (bsec[i].extra > 0)	// skip Xsector
315 		{
316 			data += 60;
317 		}
318 	}
319 
320 	// Read walls
321 	k |= 0x7474614d;
322 	for (i = 0; i < numWalls; ++i)
323 	{
324 		if (mapver == 7)
325 		{
326 			Decrypt (&bwal[i], data, sizeof(walltype), k);
327 		}
328 		else
329 		{
330 			memcpy (&bwal[i], data, sizeof(walltype));
331 		}
332 		data += sizeof(walltype);
333 		if (bwal[i].extra > 0)	// skip Xwall
334 		{
335 			data += 24;
336 		}
337 	}
338 
339 	// Read sprites
340 	k = (numRevisions * sizeof(spritetype)) | 0x7474614d;
341 	for (i = 0; i < numsprites; ++i)
342 	{
343 		if (mapver == 7)
344 		{
345 			Decrypt (&bspr[i], data, sizeof(spritetype), k);
346 		}
347 		else
348 		{
349 			memcpy (&bspr[i], data, sizeof(spritetype));
350 		}
351 		data += sizeof(spritetype);
352 		if (bspr[i].extra > 0)	// copy Xsprite
353 		{
354 			assert(sizeof(Xsprite) == 56);
355 			memcpy(&xspr[i], data, sizeof(Xsprite));
356 			data += sizeof(Xsprite);
357 		}
358 		else
359 		{
360 			memset(&xspr[i], 0, sizeof(Xsprite));
361 		}
362 	}
363 
364 	// Now convert to Doom format, since we've extracted all the standard
365 	// BUILD info from the map we need. (Sprites are ignored.)
366 	LoadSectors (bsec);
367 	LoadWalls (bwal, numWalls, bsec);
368 	*mapthings = new FMapThing[numsprites];
369 	*numspr = LoadSprites (bspr, xspr, numsprites, bsec, *mapthings);
370 
371 	delete[] bsec;
372 	delete[] bwal;
373 	delete[] bspr;
374 	delete[] xspr;
375 
376 	return true;
377 }
378 
379 //==========================================================================
380 //
381 // LoadSectors
382 //
383 //==========================================================================
384 
LoadSectors(sectortype * bsec)385 static void LoadSectors (sectortype *bsec)
386 {
387 	FDynamicColormap *map = GetSpecialLights (PalEntry (255,255,255), level.fadeto, 0);
388 	sector_t *sec;
389 	char tnam[9];
390 
391 	sec = sectors = new sector_t[numsectors];
392 	memset (sectors, 0, sizeof(sector_t)*numsectors);
393 
394 	sectors[0].e = new extsector_t[numsectors];
395 
396 	for (int i = 0; i < numsectors; ++i, ++bsec, ++sec)
397 	{
398 		bsec->wallptr = WORD(bsec->wallptr);
399 		bsec->wallnum = WORD(bsec->wallnum);
400 		bsec->ceilingstat = WORD(bsec->ceilingstat);
401 		bsec->floorstat = WORD(bsec->floorstat);
402 
403 		sec->e = &sectors[0].e[i];
404 		sec->SetPlaneTexZ(sector_t::floor, -(LittleLong(bsec->floorz) << 8));
405 		sec->floorplane.d = -sec->GetPlaneTexZ(sector_t::floor);
406 		sec->floorplane.c = FRACUNIT;
407 		sec->floorplane.ic = FRACUNIT;
408 		mysnprintf (tnam, countof(tnam), "BTIL%04d", LittleShort(bsec->floorpicnum));
409 		sec->SetTexture(sector_t::floor, TexMan.GetTexture (tnam, FTexture::TEX_Build));
410 		sec->SetXScale(sector_t::floor, (bsec->floorstat & 8) ? FRACUNIT*2 : FRACUNIT);
411 		sec->SetYScale(sector_t::floor, (bsec->floorstat & 8) ? FRACUNIT*2 : FRACUNIT);
412 		sec->SetXOffset(sector_t::floor, (bsec->floorxpanning << FRACBITS) + (32 << FRACBITS));
413 		sec->SetYOffset(sector_t::floor, bsec->floorypanning << FRACBITS);
414 		sec->SetPlaneLight(sector_t::floor, SHADE2LIGHT (bsec->floorshade));
415 		sec->ChangeFlags(sector_t::floor, 0, PLANEF_ABSLIGHTING);
416 
417 		sec->SetPlaneTexZ(sector_t::ceiling, -(LittleLong(bsec->ceilingz) << 8));
418 		sec->ceilingplane.d = sec->GetPlaneTexZ(sector_t::ceiling);
419 		sec->ceilingplane.c = -FRACUNIT;
420 		sec->ceilingplane.ic = -FRACUNIT;
421 		mysnprintf (tnam, countof(tnam), "BTIL%04d", LittleShort(bsec->ceilingpicnum));
422 		sec->SetTexture(sector_t::ceiling, TexMan.GetTexture (tnam, FTexture::TEX_Build));
423 		if (bsec->ceilingstat & 1)
424 		{
425 			sky1texture = sky2texture = sec->GetTexture(sector_t::ceiling);
426 			sec->SetTexture(sector_t::ceiling, skyflatnum);
427 		}
428 		sec->SetXScale(sector_t::ceiling, (bsec->ceilingstat & 8) ? FRACUNIT*2 : FRACUNIT);
429 		sec->SetYScale(sector_t::ceiling, (bsec->ceilingstat & 8) ? FRACUNIT*2 : FRACUNIT);
430 		sec->SetXOffset(sector_t::ceiling, (bsec->ceilingxpanning << FRACBITS) + (32 << FRACBITS));
431 		sec->SetYOffset(sector_t::ceiling, bsec->ceilingypanning << FRACBITS);
432 		sec->SetPlaneLight(sector_t::ceiling, SHADE2LIGHT (bsec->ceilingshade));
433 		sec->ChangeFlags(sector_t::ceiling, 0, PLANEF_ABSLIGHTING);
434 
435 		sec->lightlevel = (sec->GetPlaneLight(sector_t::floor) + sec->GetPlaneLight(sector_t::ceiling)) / 2;
436 
437 		sec->seqType = -1;
438 		sec->SeqName = NAME_None;
439 		sec->nextsec = -1;
440 		sec->prevsec = -1;
441 		sec->gravity = 1.f;
442 		sec->friction = ORIG_FRICTION;
443 		sec->movefactor = ORIG_FRICTION_FACTOR;
444 		sec->ColorMap = map;
445 		sec->ZoneNumber = 0xFFFF;
446 		sec->terrainnum[sector_t::ceiling] = sec->terrainnum[sector_t::floor] = -1;
447 
448 		if (bsec->floorstat & 4)
449 		{
450 			sec->SetAngle(sector_t::floor, ANGLE_90);
451 			sec->SetXScale(sector_t::floor, -sec->GetXScale(sector_t::floor));
452 		}
453 		if (bsec->floorstat & 16)
454 		{
455 			sec->SetXScale(sector_t::floor, -sec->GetXScale(sector_t::floor));
456 		}
457 		if (bsec->floorstat & 32)
458 		{
459 			sec->SetYScale(sector_t::floor, -sec->GetYScale(sector_t::floor));
460 		}
461 
462 		if (bsec->ceilingstat & 4)
463 		{
464 			sec->SetAngle(sector_t::ceiling, ANGLE_90);
465 			sec->SetYScale(sector_t::ceiling, -sec->GetYScale(sector_t::ceiling));
466 		}
467 		if (bsec->ceilingstat & 16)
468 		{
469 			sec->SetXScale(sector_t::ceiling, -sec->GetXScale(sector_t::ceiling));
470 		}
471 		if (bsec->ceilingstat & 32)
472 		{
473 			sec->SetYScale(sector_t::ceiling, -sec->GetYScale(sector_t::ceiling));
474 		}
475 	}
476 }
477 
478 //==========================================================================
479 //
480 // LoadWalls
481 //
482 //==========================================================================
483 
LoadWalls(walltype * walls,int numwalls,sectortype * bsec)484 static void LoadWalls (walltype *walls, int numwalls, sectortype *bsec)
485 {
486 	int i, j;
487 
488 	// Setting numvertexes to the same as numwalls is overly conservative,
489 	// but the extra vertices will be removed during the BSP building pass.
490 	numsides = numvertexes = numwalls;
491 	numlines = 0;
492 
493 	sides = new side_t[numsides];
494 	memset (sides, 0, numsides*sizeof(side_t));
495 
496 	vertexes = new vertex_t[numvertexes];
497 	numvertexes = 0;
498 
499 	// First mark each sidedef with the sector it belongs to
500 	for (i = 0; i < numsectors; ++i)
501 	{
502 		if (bsec[i].wallptr >= 0)
503 		{
504 			for (j = 0; j < bsec[i].wallnum; ++j)
505 			{
506 				sides[j + bsec[i].wallptr].sector = sectors + i;
507 			}
508 		}
509 	}
510 
511 	// Now copy wall properties to their matching sidedefs
512 	for (i = 0; i < numwalls; ++i)
513 	{
514 		char tnam[9];
515 		FTextureID overpic, pic;
516 
517 		mysnprintf (tnam, countof(tnam), "BTIL%04d", LittleShort(walls[i].picnum));
518 		pic = TexMan.GetTexture (tnam, FTexture::TEX_Build);
519 		mysnprintf (tnam, countof(tnam), "BTIL%04d", LittleShort(walls[i].overpicnum));
520 		overpic = TexMan.GetTexture (tnam, FTexture::TEX_Build);
521 
522 		walls[i].x = LittleLong(walls[i].x);
523 		walls[i].y = LittleLong(walls[i].y);
524 		walls[i].point2 = LittleShort(walls[i].point2);
525 		walls[i].cstat = LittleShort(walls[i].cstat);
526 		walls[i].nextwall = LittleShort(walls[i].nextwall);
527 		walls[i].nextsector = LittleShort(walls[i].nextsector);
528 
529 		sides[i].SetTextureXOffset(walls[i].xpanning << FRACBITS);
530 		sides[i].SetTextureYOffset(walls[i].ypanning << FRACBITS);
531 
532 		sides[i].SetTexture(side_t::top, pic);
533 		sides[i].SetTexture(side_t::bottom, pic);
534 		if (walls[i].nextsector < 0 || (walls[i].cstat & 32))
535 		{
536 			sides[i].SetTexture(side_t::mid, pic);
537 		}
538 		else if (walls[i].cstat & 16)
539 		{
540 			sides[i].SetTexture(side_t::mid, overpic);
541 		}
542 		else
543 		{
544 			sides[i].SetTexture(side_t::mid, FNullTextureID());
545 		}
546 
547 		sides[i].TexelLength = walls[i].xrepeat * 8;
548 		sides[i].SetTextureYScale(walls[i].yrepeat << (FRACBITS - 3));
549 		sides[i].SetTextureXScale(FRACUNIT);
550 		sides[i].SetLight(SHADE2LIGHT(walls[i].shade));
551 		sides[i].Flags = WALLF_ABSLIGHTING;
552 		sides[i].RightSide = walls[i].point2;
553 		sides[walls[i].point2].LeftSide = i;
554 
555 		if (walls[i].nextwall >= 0 && walls[i].nextwall <= i)
556 		{
557 			sides[i].linedef = sides[walls[i].nextwall].linedef;
558 		}
559 		else
560 		{
561 			sides[i].linedef = (line_t*)(intptr_t)(numlines++);
562 		}
563 	}
564 
565 	// Set line properties that Doom doesn't store per-sidedef
566 	lines = new line_t[numlines];
567 	memset (lines, 0, numlines*sizeof(line_t));
568 
569 	for (i = 0, j = -1; i < numwalls; ++i)
570 	{
571 		if (walls[i].nextwall >= 0 && walls[i].nextwall <= i)
572 		{
573 			continue;
574 		}
575 
576 		j = int(intptr_t(sides[i].linedef));
577 		lines[j].sidedef[0] = (side_t*)(intptr_t)i;
578 		lines[j].sidedef[1] = (side_t*)(intptr_t)walls[i].nextwall;
579 		lines[j].v1 = FindVertex (walls[i].x, walls[i].y);
580 		lines[j].v2 = FindVertex (walls[walls[i].point2].x, walls[walls[i].point2].y);
581 		lines[j].frontsector = sides[i].sector;
582 		lines[j].flags |= ML_WRAP_MIDTEX;
583 		if (walls[i].nextsector >= 0)
584 		{
585 			lines[j].backsector = sectors + walls[i].nextsector;
586 			lines[j].flags |= ML_TWOSIDED;
587 		}
588 		else
589 		{
590 			lines[j].backsector = NULL;
591 		}
592 		P_AdjustLine (&lines[j]);
593 		if (walls[i].cstat & 128)
594 		{
595 			if (walls[i].cstat & 512)
596 			{
597 				lines[j].Alpha = FRACUNIT/3;
598 			}
599 			else
600 			{
601 				lines[j].Alpha = FRACUNIT*2/3;
602 			}
603 		}
604 		if (walls[i].cstat & 1)
605 		{
606 			lines[j].flags |= ML_BLOCKING;
607 		}
608 		if (walls[i].nextwall < 0)
609 		{
610 			if (walls[i].cstat & 4)
611 			{
612 				lines[j].flags |= ML_DONTPEGBOTTOM;
613 			}
614 		}
615 		else
616 		{
617 			if (walls[i].cstat & 4)
618 			{
619 				lines[j].flags |= ML_DONTPEGTOP;
620 			}
621 			else
622 			{
623 				lines[j].flags |= ML_DONTPEGBOTTOM;
624 			}
625 		}
626 		if (walls[i].cstat & 64)
627 		{
628 			lines[j].flags |= ML_BLOCKEVERYTHING;
629 		}
630 	}
631 
632 	// Finish setting sector properties that depend on walls
633 	for (i = 0; i < numsectors; ++i, ++bsec)
634 	{
635 		SlopeWork slope;
636 
637 		slope.wal = &walls[bsec->wallptr];
638 		slope.wal2 = &walls[slope.wal->point2];
639 		slope.dx = slope.wal2->x - slope.wal->x;
640 		slope.dy = slope.wal2->y - slope.wal->y;
641 		slope.i = long (sqrt ((double)(slope.dx*slope.dx+slope.dy*slope.dy))) << 5;
642 		if (slope.i == 0)
643 		{
644 			continue;
645 		}
646 		if ((bsec->floorstat & 2) && (bsec->floorheinum != 0))
647 		{ // floor is sloped
648 			slope.heinum = -LittleShort(bsec->floorheinum);
649 			slope.z[0] = slope.z[1] = slope.z[2] = -bsec->floorz;
650 			CalcPlane (slope, sectors[i].floorplane);
651 		}
652 		if ((bsec->ceilingstat & 2) && (bsec->ceilingheinum != 0))
653 		{ // ceiling is sloped
654 			slope.heinum = -LittleShort(bsec->ceilingheinum);
655 			slope.z[0] = slope.z[1] = slope.z[2] = -bsec->ceilingz;
656 			CalcPlane (slope, sectors[i].ceilingplane);
657 		}
658 		int linenum = int(intptr_t(sides[bsec->wallptr].linedef));
659 		int sidenum = int(intptr_t(lines[linenum].sidedef[1]));
660 		if (bsec->floorstat & 64)
661 		{ // floor is aligned to first wall
662 			P_AlignFlat (linenum, sidenum == bsec->wallptr, 0);
663 		}
664 		if (bsec->ceilingstat & 64)
665 		{ // ceiling is aligned to first wall
666 			P_AlignFlat (linenum, sidenum == bsec->wallptr, 0);
667 		}
668 	}
669 	for (i = 0; i < numlines; i++)
670 	{
671 		intptr_t front = intptr_t(lines[i].sidedef[0]);
672 		intptr_t back = intptr_t(lines[i].sidedef[1]);
673 		lines[i].sidedef[0] = front >= 0 ? &sides[front] : NULL;
674 		lines[i].sidedef[1] = back >= 0 ? &sides[back] : NULL;
675 	}
676 	for (i = 0; i < numsides; i++)
677 	{
678 		assert(sides[i].sector != NULL);
679 		sides[i].linedef = &lines[intptr_t(sides[i].linedef)];
680 	}
681 }
682 
683 //==========================================================================
684 //
685 // LoadSprites
686 //
687 //==========================================================================
688 
LoadSprites(spritetype * sprites,Xsprite * xsprites,int numsprites,sectortype * bsectors,FMapThing * mapthings)689 static int LoadSprites (spritetype *sprites, Xsprite *xsprites, int numsprites,
690 	sectortype *bsectors, FMapThing *mapthings)
691 {
692 	int count = 0;
693 
694 	memset(mapthings, 0, sizeof(*mapthings)*numsprites);
695 
696 	for (int i = 0; i < numsprites; ++i)
697 	{
698 		mapthings[count].thingid = 0;
699 		mapthings[count].x = (sprites[i].x << 12);
700 		mapthings[count].y = -(sprites[i].y << 12);
701 		mapthings[count].z = (bsectors[sprites[i].sectnum].floorz - sprites[i].z) << 8;
702 		mapthings[count].angle = (((2048-sprites[i].ang) & 2047) * 360) >> 11;
703 		mapthings[count].ClassFilter = 0xffff;
704 		mapthings[count].SkillFilter = 0xffff;
705 		mapthings[count].flags = MTF_SINGLE|MTF_COOPERATIVE|MTF_DEATHMATCH;
706 		mapthings[count].special = 0;
707 		mapthings[count].gravity = FRACUNIT;
708 		mapthings[count].RenderStyle = STYLE_Count;
709 		mapthings[count].alpha = -1;
710 		mapthings[count].health = -1;
711 		mapthings[count].FloatbobPhase = -1;
712 
713 		if (xsprites != NULL && sprites[i].lotag == 710)
714 		{ // Blood ambient sound
715 			mapthings[count].args[0] = xsprites[i].Data3;
716 			// I am totally guessing about the volume level. 50 seems to be a pretty
717 			// typical value for Blood's standard maps, so I assume it's 100-based.
718 			mapthings[count].args[1] = xsprites[i].Data4;
719 			mapthings[count].args[2] = xsprites[i].Data1;
720 			mapthings[count].args[3] = xsprites[i].Data2;
721 			mapthings[count].EdNum = 14065;
722 		}
723 		else if (xsprites != NULL && sprites[i].lotag == 1)
724 		{ // Blood player start
725 			if (xsprites[i].Data1 < 4)
726 				mapthings[count].EdNum= 1 + xsprites[i].Data1;
727 			else
728 				mapthings[count].EdNum = 4001 + xsprites[i].Data1 - 4;
729 		}
730 		else if (xsprites != NULL && sprites[i].lotag == 2)
731 		{ // Bloodbath start
732 			mapthings[count].EdNum = 11;
733 		}
734 		else
735 		{
736 			if (sprites[i].cstat & 32768) continue;
737 			if (sprites[i].xrepeat == 0 || sprites[i].yrepeat == 0) continue;
738 
739 			mapthings[count].EdNum = 9988;
740 			mapthings[count].args[0] = sprites[i].picnum;
741 			mapthings[count].args[2] = sprites[i].xrepeat;
742 			mapthings[count].args[3] = sprites[i].yrepeat;
743 			mapthings[count].args[4] = sprites[i].cstat;
744 		}
745 		mapthings[count].info = DoomEdMap.CheckKey(mapthings[count].EdNum);
746 		count++;
747 	}
748 	return count;
749 }
750 
751 //==========================================================================
752 //
753 // FindVertex
754 //
755 //==========================================================================
756 
FindVertex(fixed_t x,fixed_t y)757 vertex_t *FindVertex (fixed_t x, fixed_t y)
758 {
759 	int i;
760 
761 	x <<= 12;
762 	y = -(y << 12);
763 
764 	for (i = 0; i < numvertexes; ++i)
765 	{
766 		if (vertexes[i].x == x && vertexes[i].y == y)
767 		{
768 			return &vertexes[i];
769 		}
770 	}
771 	vertexes[i].x = x;
772 	vertexes[i].y = y;
773 	numvertexes++;
774 	return &vertexes[i];
775 }
776 
777 //==========================================================================
778 //
779 // CreateStartSpot
780 //
781 //==========================================================================
782 
CreateStartSpot(fixed_t * pos,FMapThing * start)783 static void CreateStartSpot (fixed_t *pos, FMapThing *start)
784 {
785 	short angle = LittleShort(*(WORD *)(&pos[3]));
786 	FMapThing mt = { 0, };
787 
788 	mt.x = LittleLong(pos[0])<<12;
789 	mt.y = (-LittleLong(pos[1]))<<12;
790 	mt.angle = short(Scale((2048-angle)&2047, 360, 2048));
791 	mt.info = DoomEdMap.CheckKey(1);
792 	mt.EdNum = 1;
793 	mt.flags = 7|MTF_SINGLE|224;
794 
795 	*start = mt;
796 }
797 
798 //==========================================================================
799 //
800 // CalcPlane
801 //
802 //==========================================================================
803 
CalcPlane(SlopeWork & slope,secplane_t & plane)804 static void CalcPlane (SlopeWork &slope, secplane_t &plane)
805 {
806 	FVector3 pt[3];
807 	long j;
808 
809 	slope.x[0] = slope.wal->x;  slope.y[0] = slope.wal->y;
810 	slope.x[1] = slope.wal2->x; slope.y[1] = slope.wal2->y;
811 	if (slope.dx == 0)
812 	{
813 		slope.x[2] = slope.x[0] + 64;
814 		slope.y[2] = slope.y[0];
815 	}
816 	else
817 	{
818 		slope.x[2] = slope.x[0];
819 		slope.y[2] = slope.y[0] + 64;
820 	}
821 	j = DMulScale3 (slope.dx, slope.y[2]-slope.wal->y,
822 		-slope.dy, slope.x[2]-slope.wal->x);
823 	slope.z[2] += Scale (slope.heinum, j, slope.i);
824 
825 	pt[0] = FVector3(slope.dx, -slope.dy, 0);
826 	pt[1] = FVector3(slope.x[2] - slope.x[0], slope.y[0] - slope.y[2], (slope.z[2] - slope.z[0]) / 16);
827 	pt[2] = (pt[0] ^ pt[1]).Unit();
828 
829 	if ((pt[2][2] < 0 && plane.c > 0) || (pt[2][2] > 0 && plane.c < 0))
830 	{
831 		pt[2] = -pt[2];
832 	}
833 
834 	plane.a = fixed_t(pt[2][0]*65536.f);
835 	plane.b = fixed_t(pt[2][1]*65536.f);
836 	plane.c = fixed_t(pt[2][2]*65536.f);
837 	plane.ic = fixed_t(65536.f/pt[2][2]);
838 	plane.d = -TMulScale8
839 		(plane.a, slope.x[0]<<4, plane.b, (-slope.y[0])<<4, plane.c, slope.z[0]);
840 }
841 
842 //==========================================================================
843 //
844 // Decrypt
845 //
846 // Note that this is different from the general RFF encryption.
847 //
848 //==========================================================================
849 
Decrypt(void * to_,const void * from_,int len,int key)850 static void Decrypt (void *to_, const void *from_, int len, int key)
851 {
852 	BYTE *to = (BYTE *)to_;
853 	const BYTE *from = (const BYTE *)from_;
854 
855 	for (int i = 0; i < len; ++i, ++key)
856 	{
857 		to[i] = from[i] ^ key;
858 	}
859 }
860 
861 //==========================================================================
862 //
863 // Just an actor to make the Build sprites show up. It doesn't do anything
864 // with them other than display them.
865 //
866 //==========================================================================
867 
868 class ACustomSprite : public AActor
869 {
870 	DECLARE_CLASS (ACustomSprite, AActor);
871 public:
872 	void BeginPlay ();
873 };
874 
IMPLEMENT_CLASS(ACustomSprite)875 IMPLEMENT_CLASS (ACustomSprite)
876 
877 void ACustomSprite::BeginPlay ()
878 {
879 	char name[9];
880 	Super::BeginPlay ();
881 
882 	mysnprintf (name, countof(name), "BTIL%04d", args[0] & 0xffff);
883 	picnum = TexMan.GetTexture (name, FTexture::TEX_Build);
884 
885 	scaleX = args[2] * (FRACUNIT/64);
886 	scaleY = args[3] * (FRACUNIT/64);
887 
888 	int cstat = args[4];
889 	if (cstat & 2)
890 	{
891 		RenderStyle = STYLE_Translucent;
892 		alpha = (cstat & 512) ? TRANSLUC66 : TRANSLUC33;
893 	}
894 	if (cstat & 4)
895 		renderflags |= RF_XFLIP;
896 	if (cstat & 8)
897 		renderflags |= RF_YFLIP;
898 	// set face/wall/floor flags
899 	renderflags |= ActorRenderFlags::FromInt (((cstat >> 4) & 3) << 12);
900 }
901