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 = §ors[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