aboutsummaryrefslogtreecommitdiff
path: root/src/p_setup.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/p_setup.c')
-rw-r--r--src/p_setup.c1688
1 files changed, 1688 insertions, 0 deletions
diff --git a/src/p_setup.c b/src/p_setup.c
new file mode 100644
index 0000000..5247cb9
--- /dev/null
+++ b/src/p_setup.c
@@ -0,0 +1,1688 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2000 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
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 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Do all the WAD I/O, get map description,
31 * set up initial state and misc. LUTs.
32 *
33 *-----------------------------------------------------------------------------*/
34
35#include <math.h>
36
37#include "doomstat.h"
38#include "m_bbox.h"
39#include "m_argv.h"
40#include "g_game.h"
41#include "w_wad.h"
42#include "r_main.h"
43#include "r_things.h"
44#include "p_maputl.h"
45#include "p_map.h"
46#include "p_setup.h"
47#include "p_spec.h"
48#include "p_tick.h"
49#include "p_enemy.h"
50#include "s_sound.h"
51#include "lprintf.h" //jff 10/6/98 for debug outputs
52#include "v_video.h"
53#include "r_demo.h"
54#include "r_fps.h"
55
56//
57// MAP related Lookup tables.
58// Store VERTEXES, LINEDEFS, SIDEDEFS, etc.
59//
60
61int numvertexes;
62vertex_t *vertexes;
63
64int numsegs;
65seg_t *segs;
66
67int numsectors;
68sector_t *sectors;
69
70int numsubsectors;
71subsector_t *subsectors;
72
73int numnodes;
74node_t *nodes;
75
76int numlines;
77line_t *lines;
78
79int numsides;
80side_t *sides;
81
82
83////////////////////////////////////////////////////////////////////////////////////////////
84// figgi 08/21/00 -- constants and globals for glBsp support
85#define gNd2 0x32644E67 // figgi -- suppport for new GL_VERT format v2.0
86#define gNd3 0x33644E67
87#define gNd4 0x34644E67
88#define gNd5 0x35644E67
89#define ZNOD 0x444F4E5A
90#define ZGLN 0x4E4C475A
91#define GL_VERT_OFFSET 4
92
93int firstglvertex = 0;
94int nodesVersion = 0;
95boolean forceOldBsp = false;
96
97// figgi 08/21/00 -- glSegs
98typedef struct
99{
100 unsigned short v1; // start vertex (16 bit)
101 unsigned short v2; // end vertex (16 bit)
102 unsigned short linedef; // linedef, or -1 for minisegs
103 short side; // side on linedef: 0 for right, 1 for left
104 unsigned short partner; // corresponding partner seg, or -1 on one-sided walls
105} glseg_t;
106
107// fixed 32 bit gl_vert format v2.0+ (glBsp 1.91)
108typedef struct
109{
110 fixed_t x,y;
111} mapglvertex_t;
112
113enum
114{
115 ML_GL_LABEL=0, // A separator name, GL_ExMx or GL_MAPxx
116 ML_GL_VERTS, // Extra Vertices
117 ML_GL_SEGS, // Segs, from linedefs & minisegs
118 ML_GL_SSECT, // SubSectors, list of segs
119 ML_GL_NODES // GL BSP nodes
120};
121////////////////////////////////////////////////////////////////////////////////////////////
122
123
124// BLOCKMAP
125// Created from axis aligned bounding box
126// of the map, a rectangular array of
127// blocks of size ...
128// Used to speed up collision detection
129// by spatial subdivision in 2D.
130//
131// Blockmap size.
132
133int bmapwidth, bmapheight; // size in mapblocks
134
135// killough 3/1/98: remove blockmap limit internally:
136long *blockmap; // was short -- killough
137
138// offsets in blockmap are from here
139long *blockmaplump; // was short -- killough
140
141fixed_t bmaporgx, bmaporgy; // origin of block map
142
143mobj_t **blocklinks; // for thing chains
144
145//
146// REJECT
147// For fast sight rejection.
148// Speeds up enemy AI by skipping detailed
149// LineOf Sight calculation.
150// Without the special effect, this could
151// be used as a PVS lookup as well.
152//
153
154static int rejectlump = -1;// cph - store reject lump num if cached
155const byte *rejectmatrix; // cph - const*
156
157// Maintain single and multi player starting spots.
158
159// 1/11/98 killough: Remove limit on deathmatch starts
160mapthing_t *deathmatchstarts; // killough
161size_t num_deathmatchstarts; // killough
162
163mapthing_t *deathmatch_p;
164mapthing_t playerstarts[MAXPLAYERS];
165
166//
167// P_CheckForZDoomNodes
168//
169
170static boolean P_CheckForZDoomNodes(int lumpnum, int gl_lumpnum)
171{
172 const void *data;
173
174 data = W_CacheLumpNum(lumpnum + ML_NODES);
175 if (*(const int *)data == ZNOD)
176 I_Error("P_CheckForZDoomNodes: ZDoom nodes not supported yet");
177
178 data = W_CacheLumpNum(lumpnum + ML_SSECTORS);
179 if (*(const int *)data == ZGLN)
180 I_Error("P_CheckForZDoomNodes: ZDoom GL nodes not supported yet");
181
182 return false;
183}
184
185//
186// P_GetNodesVersion
187//
188
189static void P_GetNodesVersion(int lumpnum, int gl_lumpnum)
190{
191 const void *data;
192
193 data = W_CacheLumpNum(gl_lumpnum+ML_GL_VERTS);
194 if ( (gl_lumpnum > lumpnum) && (forceOldBsp == false) && (compatibility_level >= prboom_2_compatibility) ) {
195 if (*(const int *)data == gNd2) {
196 data = W_CacheLumpNum(gl_lumpnum+ML_GL_SEGS);
197 if (*(const int *)data == gNd3) {
198 nodesVersion = gNd3;
199 lprintf(LO_DEBUG, "P_GetNodesVersion: found version 3 nodes\n");
200 I_Error("P_GetNodesVersion: version 3 nodes not supported\n");
201 } else {
202 nodesVersion = gNd2;
203 lprintf(LO_DEBUG, "P_GetNodesVersion: found version 2 nodes\n");
204 }
205 }
206 if (*(const int *)data == gNd4) {
207 nodesVersion = gNd4;
208 lprintf(LO_DEBUG, "P_GetNodesVersion: found version 4 nodes\n");
209 I_Error("P_GetNodesVersion: version 4 nodes not supported\n");
210 }
211 if (*(const int *)data == gNd5) {
212 nodesVersion = gNd5;
213 lprintf(LO_DEBUG, "P_GetNodesVersion: found version 5 nodes\n");
214 I_Error("P_GetNodesVersion: version 5 nodes not supported\n");
215 }
216 } else {
217 nodesVersion = 0;
218 lprintf(LO_DEBUG,"P_GetNodesVersion: using normal BSP nodes\n");
219 if (P_CheckForZDoomNodes(lumpnum, gl_lumpnum))
220 I_Error("P_GetNodesVersion: ZDoom nodes not supported yet");
221 }
222}
223
224//
225// P_LoadVertexes
226//
227// killough 5/3/98: reformatted, cleaned up
228//
229static void P_LoadVertexes (int lump)
230{
231 const mapvertex_t *data; // cph - const
232 int i;
233
234 // Determine number of lumps:
235 // total lump length / vertex record length.
236 numvertexes = W_LumpLength(lump) / sizeof(mapvertex_t);
237
238 // Allocate zone memory for buffer.
239 vertexes = Z_Malloc(numvertexes*sizeof(vertex_t),PU_LEVEL,0);
240
241 // Load data into cache.
242 // cph 2006/07/29 - cast to mapvertex_t here, making the loop below much neater
243 data = (const mapvertex_t *)W_CacheLumpNum(lump);
244
245 // Copy and convert vertex coordinates,
246 // internal representation as fixed.
247 for (i=0; i<numvertexes; i++)
248 {
249 vertexes[i].x = SHORT(data[i].x)<<FRACBITS;
250 vertexes[i].y = SHORT(data[i].y)<<FRACBITS;
251 }
252
253 // Free buffer memory.
254 W_UnlockLumpNum(lump);
255}
256
257/*******************************************
258 * Name : P_LoadVertexes2 *
259 * modified : 09/18/00, adapted for PrBoom *
260 * author : figgi *
261 * what : support for gl nodes *
262 *******************************************/
263
264// figgi -- FIXME: Automap showes wrong zoom boundaries when starting game
265// when P_LoadVertexes2 is used with classic BSP nodes.
266
267static void P_LoadVertexes2(int lump, int gllump)
268{
269 const byte *gldata;
270 int i;
271 const mapvertex_t* ml;
272
273 firstglvertex = W_LumpLength(lump) / sizeof(mapvertex_t);
274 numvertexes = W_LumpLength(lump) / sizeof(mapvertex_t);
275
276 if (gllump >= 0) // check for glVertices
277 {
278 gldata = W_CacheLumpNum(gllump);
279
280 if (nodesVersion == gNd2) // 32 bit GL_VERT format (16.16 fixed)
281 {
282 const mapglvertex_t* mgl;
283
284 numvertexes += (W_LumpLength(gllump) - GL_VERT_OFFSET)/sizeof(mapglvertex_t);
285 vertexes = Z_Malloc (numvertexes*sizeof(vertex_t),PU_LEVEL,0);
286 mgl = (const mapglvertex_t *) (gldata + GL_VERT_OFFSET);
287
288 for (i = firstglvertex; i < numvertexes; i++)
289 {
290 vertexes[i].x = mgl->x;
291 vertexes[i].y = mgl->y;
292 mgl++;
293 }
294 }
295 else
296 {
297 numvertexes += W_LumpLength(gllump)/sizeof(mapvertex_t);
298 vertexes = Z_Malloc (numvertexes*sizeof(vertex_t),PU_LEVEL,0);
299 ml = (const mapvertex_t *)gldata;
300
301 for (i = firstglvertex; i < numvertexes; i++)
302 {
303 vertexes[i].x = SHORT(ml->x)<<FRACBITS;
304 vertexes[i].y = SHORT(ml->y)<<FRACBITS;
305 ml++;
306 }
307 }
308 W_UnlockLumpNum(gllump);
309 }
310
311 ml = (const mapvertex_t*) W_CacheLumpNum(lump);
312
313 for (i=0; i < firstglvertex; i++)
314 {
315 vertexes[i].x = SHORT(ml->x)<<FRACBITS;
316 vertexes[i].y = SHORT(ml->y)<<FRACBITS;
317 ml++;
318 }
319 W_UnlockLumpNum(lump);
320}
321
322
323/*******************************************
324 * created : 08/13/00 *
325 * modified : 09/18/00, adapted for PrBoom *
326 * author : figgi *
327 * what : basic functions needed for *
328 * computing gl nodes *
329 *******************************************/
330
331static int checkGLVertex(int num)
332{
333 if (num & 0x8000)
334 num = (num&0x7FFF)+firstglvertex;
335 return num;
336}
337
338
339static float GetDistance(int dx, int dy)
340{
341 float fx = (float)(dx)/FRACUNIT, fy = (float)(dy)/FRACUNIT;
342 return (float)sqrt(fx*fx + fy*fy);
343}
344
345
346static int GetOffset(vertex_t *v1, vertex_t *v2)
347{
348 float a, b;
349 int r;
350 a = (float)(v1->x - v2->x) / (float)FRACUNIT;
351 b = (float)(v1->y - v2->y) / (float)FRACUNIT;
352 r = (int)(sqrt(a*a+b*b) * (float)FRACUNIT);
353 return r;
354}
355
356
357
358//
359// P_LoadSegs
360//
361// killough 5/3/98: reformatted, cleaned up
362
363static void P_LoadSegs (int lump)
364{
365 int i;
366 const mapseg_t *data; // cph - const
367
368 numsegs = W_LumpLength(lump) / sizeof(mapseg_t);
369 segs = Z_Calloc(numsegs,sizeof(seg_t),PU_LEVEL,0);
370 data = (const mapseg_t *)W_CacheLumpNum(lump); // cph - wad lump handling updated
371
372 if ((!data) || (!numsegs))
373 I_Error("P_LoadSegs: no segs in level");
374
375 for (i=0; i<numsegs; i++)
376 {
377 seg_t *li = segs+i;
378 const mapseg_t *ml = data + i;
379 unsigned short v1, v2;
380
381 int side, linedef;
382 line_t *ldef;
383
384 li->iSegID = i; // proff 11/05/2000: needed for OpenGL
385
386 v1 = (unsigned short)SHORT(ml->v1);
387 v2 = (unsigned short)SHORT(ml->v2);
388 li->v1 = &vertexes[v1];
389 li->v2 = &vertexes[v2];
390
391 li->miniseg = false; // figgi -- there are no minisegs in classic BSP nodes
392 li->length = GetDistance(li->v2->x - li->v1->x, li->v2->y - li->v1->y);
393 li->angle = (SHORT(ml->angle))<<16;
394 li->offset =(SHORT(ml->offset))<<16;
395 linedef = (unsigned short)SHORT(ml->linedef);
396 ldef = &lines[linedef];
397 li->linedef = ldef;
398 side = SHORT(ml->side);
399 li->sidedef = &sides[ldef->sidenum[side]];
400
401 /* cph 2006/09/30 - our frontsector can be the second side of the
402 * linedef, so must check for NO_INDEX in case we are incorrectly
403 * referencing the back of a 1S line */
404 if (ldef->sidenum[side] != NO_INDEX)
405 li->frontsector = sides[ldef->sidenum[side]].sector;
406 else {
407 li->frontsector = 0;
408 lprintf(LO_WARN, "P_LoadSegs: front of seg %i has no sidedef\n", i);
409 }
410
411 if (ldef->flags & ML_TWOSIDED && ldef->sidenum[side^1]!=NO_INDEX)
412 li->backsector = sides[ldef->sidenum[side^1]].sector;
413 else
414 li->backsector = 0;
415 }
416
417 W_UnlockLumpNum(lump); // cph - release the data
418}
419
420
421
422/*******************************************
423 * Name : P_LoadGLSegs *
424 * created : 08/13/00 *
425 * modified : 09/18/00, adapted for PrBoom *
426 * author : figgi *
427 * what : support for gl nodes *
428 *******************************************/
429static void P_LoadGLSegs(int lump)
430{
431 int i;
432 const glseg_t *ml;
433 line_t *ldef;
434
435 numsegs = W_LumpLength(lump) / sizeof(glseg_t);
436 segs = Z_Malloc(numsegs * sizeof(seg_t), PU_LEVEL, 0);
437 memset(segs, 0, numsegs * sizeof(seg_t));
438 ml = (const glseg_t*)W_CacheLumpNum(lump);
439
440 if ((!ml) || (!numsegs))
441 I_Error("P_LoadGLSegs: no glsegs in level");
442
443 for(i = 0; i < numsegs; i++)
444 { // check for gl-vertices
445 segs[i].v1 = &vertexes[checkGLVertex(SHORT(ml->v1))];
446 segs[i].v2 = &vertexes[checkGLVertex(SHORT(ml->v2))];
447 segs[i].iSegID = i;
448
449 if(ml->linedef != (unsigned short)-1) // skip minisegs
450 {
451 ldef = &lines[ml->linedef];
452 segs[i].linedef = ldef;
453 segs[i].miniseg = false;
454 segs[i].angle = R_PointToAngle2(segs[i].v1->x,segs[i].v1->y,segs[i].v2->x,segs[i].v2->y);
455
456 segs[i].sidedef = &sides[ldef->sidenum[ml->side]];
457 segs[i].length = GetDistance(segs[i].v2->x - segs[i].v1->x, segs[i].v2->y - segs[i].v1->y);
458 segs[i].frontsector = sides[ldef->sidenum[ml->side]].sector;
459 if (ldef->flags & ML_TWOSIDED)
460 segs[i].backsector = sides[ldef->sidenum[ml->side^1]].sector;
461 else
462 segs[i].backsector = 0;
463
464 if (ml->side)
465 segs[i].offset = GetOffset(segs[i].v1, ldef->v2);
466 else
467 segs[i].offset = GetOffset(segs[i].v1, ldef->v1);
468 }
469 else
470 {
471 segs[i].miniseg = true;
472 segs[i].angle = 0;
473 segs[i].offset = 0;
474 segs[i].length = 0;
475 segs[i].linedef = NULL;
476 segs[i].sidedef = NULL;
477 segs[i].frontsector = NULL;
478 segs[i].backsector = NULL;
479 }
480 ml++;
481 }
482 W_UnlockLumpNum(lump);
483}
484
485//
486// P_LoadSubsectors
487//
488// killough 5/3/98: reformatted, cleaned up
489
490static void P_LoadSubsectors (int lump)
491{
492 /* cph 2006/07/29 - make data a const mapsubsector_t *, so the loop below is simpler & gives no constness warnings */
493 const mapsubsector_t *data;
494 int i;
495
496 numsubsectors = W_LumpLength (lump) / sizeof(mapsubsector_t);
497 subsectors = Z_Calloc(numsubsectors,sizeof(subsector_t),PU_LEVEL,0);
498 data = (const mapsubsector_t *)W_CacheLumpNum(lump);
499
500 if ((!data) || (!numsubsectors))
501 I_Error("P_LoadSubsectors: no subsectors in level");
502
503 for (i=0; i<numsubsectors; i++)
504 {
505 subsectors[i].numlines = (unsigned short)SHORT(data[i].numsegs );
506 subsectors[i].firstline = (unsigned short)SHORT(data[i].firstseg);
507 }
508
509 W_UnlockLumpNum(lump); // cph - release the data
510}
511
512//
513// P_LoadSectors
514//
515// killough 5/3/98: reformatted, cleaned up
516
517static void P_LoadSectors (int lump)
518{
519 const byte *data; // cph - const*
520 int i;
521
522 numsectors = W_LumpLength (lump) / sizeof(mapsector_t);
523 sectors = Z_Calloc (numsectors,sizeof(sector_t),PU_LEVEL,0);
524 data = W_CacheLumpNum (lump); // cph - wad lump handling updated
525
526 for (i=0; i<numsectors; i++)
527 {
528 sector_t *ss = sectors + i;
529 const mapsector_t *ms = (const mapsector_t *) data + i;
530
531 ss->iSectorID=i; // proff 04/05/2000: needed for OpenGL
532 ss->floorheight = SHORT(ms->floorheight)<<FRACBITS;
533 ss->ceilingheight = SHORT(ms->ceilingheight)<<FRACBITS;
534 ss->floorpic = R_FlatNumForName(ms->floorpic);
535 ss->ceilingpic = R_FlatNumForName(ms->ceilingpic);
536 ss->lightlevel = SHORT(ms->lightlevel);
537 ss->special = SHORT(ms->special);
538 ss->oldspecial = SHORT(ms->special);
539 ss->tag = SHORT(ms->tag);
540 ss->thinglist = NULL;
541 ss->touching_thinglist = NULL; // phares 3/14/98
542
543 ss->nextsec = -1; //jff 2/26/98 add fields to support locking out
544 ss->prevsec = -1; // stair retriggering until build completes
545
546 // killough 3/7/98:
547 ss->floor_xoffs = 0;
548 ss->floor_yoffs = 0; // floor and ceiling flats offsets
549 ss->ceiling_xoffs = 0;
550 ss->ceiling_yoffs = 0;
551 ss->heightsec = -1; // sector used to get floor and ceiling height
552 ss->floorlightsec = -1; // sector used to get floor lighting
553 // killough 3/7/98: end changes
554
555 // killough 4/11/98 sector used to get ceiling lighting:
556 ss->ceilinglightsec = -1;
557
558 // killough 4/4/98: colormaps:
559 ss->bottommap = ss->midmap = ss->topmap = 0;
560
561 // killough 10/98: sky textures coming from sidedefs:
562 ss->sky = 0;
563 }
564
565 W_UnlockLumpNum(lump); // cph - release the data
566}
567
568
569//
570// P_LoadNodes
571//
572// killough 5/3/98: reformatted, cleaned up
573
574static void P_LoadNodes (int lump)
575{
576 const byte *data; // cph - const*
577 int i;
578
579 numnodes = W_LumpLength (lump) / sizeof(mapnode_t);
580 nodes = Z_Malloc (numnodes*sizeof(node_t),PU_LEVEL,0);
581 data = W_CacheLumpNum (lump); // cph - wad lump handling updated
582
583 if ((!data) || (!numnodes))
584 {
585 // allow trivial maps
586 if (numsubsectors == 1)
587 lprintf(LO_INFO,
588 "P_LoadNodes: trivial map (no nodes, one subsector)\n");
589 else
590 I_Error("P_LoadNodes: no nodes in level");
591 }
592
593 for (i=0; i<numnodes; i++)
594 {
595 node_t *no = nodes + i;
596 const mapnode_t *mn = (const mapnode_t *) data + i;
597 int j;
598
599 no->x = SHORT(mn->x)<<FRACBITS;
600 no->y = SHORT(mn->y)<<FRACBITS;
601 no->dx = SHORT(mn->dx)<<FRACBITS;
602 no->dy = SHORT(mn->dy)<<FRACBITS;
603
604 for (j=0 ; j<2 ; j++)
605 {
606 int k;
607 no->children[j] = SHORT(mn->children[j]);
608 for (k=0 ; k<4 ; k++)
609 no->bbox[j][k] = SHORT(mn->bbox[j][k])<<FRACBITS;
610 }
611 }
612
613 W_UnlockLumpNum(lump); // cph - release the data
614}
615
616
617/*
618 * P_LoadThings
619 *
620 * killough 5/3/98: reformatted, cleaned up
621 * cph 2001/07/07 - don't write into the lump cache, especially non-idepotent
622 * changes like byte order reversals. Take a copy to edit.
623 */
624
625static void P_LoadThings (int lump)
626{
627 int i, numthings = W_LumpLength (lump) / sizeof(mapthing_t);
628 const mapthing_t *data = W_CacheLumpNum (lump);
629
630 if ((!data) || (!numthings))
631 I_Error("P_LoadThings: no things in level");
632
633 for (i=0; i<numthings; i++)
634 {
635 mapthing_t mt = data[i];
636
637 mt.x = SHORT(mt.x);
638 mt.y = SHORT(mt.y);
639 mt.angle = SHORT(mt.angle);
640 mt.type = SHORT(mt.type);
641 mt.options = SHORT(mt.options);
642
643 if (!P_IsDoomnumAllowed(mt.type))
644 continue;
645
646 // Do spawn all other stuff.
647 P_SpawnMapThing(&mt);
648 }
649
650 W_UnlockLumpNum(lump); // cph - release the data
651}
652
653//
654// P_LoadLineDefs
655// Also counts secret lines for intermissions.
656// ^^^
657// ??? killough ???
658// Does this mean secrets used to be linedef-based, rather than sector-based?
659//
660// killough 4/4/98: split into two functions, to allow sidedef overloading
661//
662// killough 5/3/98: reformatted, cleaned up
663
664static void P_LoadLineDefs (int lump)
665{
666 const byte *data; // cph - const*
667 int i;
668
669 numlines = W_LumpLength (lump) / sizeof(maplinedef_t);
670 lines = Z_Calloc (numlines,sizeof(line_t),PU_LEVEL,0);
671 data = W_CacheLumpNum (lump); // cph - wad lump handling updated
672
673 for (i=0; i<numlines; i++)
674 {
675 const maplinedef_t *mld = (const maplinedef_t *) data + i;
676 line_t *ld = lines+i;
677 vertex_t *v1, *v2;
678
679 ld->flags = (unsigned short)SHORT(mld->flags);
680 ld->special = SHORT(mld->special);
681 ld->tag = SHORT(mld->tag);
682 v1 = ld->v1 = &vertexes[(unsigned short)SHORT(mld->v1)];
683 v2 = ld->v2 = &vertexes[(unsigned short)SHORT(mld->v2)];
684 ld->dx = v2->x - v1->x;
685 ld->dy = v2->y - v1->y;
686
687 ld->tranlump = -1; // killough 4/11/98: no translucency by default
688
689 ld->slopetype = !ld->dx ? ST_VERTICAL : !ld->dy ? ST_HORIZONTAL :
690 FixedDiv(ld->dy, ld->dx) > 0 ? ST_POSITIVE : ST_NEGATIVE;
691
692 if (v1->x < v2->x)
693 {
694 ld->bbox[BOXLEFT] = v1->x;
695 ld->bbox[BOXRIGHT] = v2->x;
696 }
697 else
698 {
699 ld->bbox[BOXLEFT] = v2->x;
700 ld->bbox[BOXRIGHT] = v1->x;
701 }
702 if (v1->y < v2->y)
703 {
704 ld->bbox[BOXBOTTOM] = v1->y;
705 ld->bbox[BOXTOP] = v2->y;
706 }
707 else
708 {
709 ld->bbox[BOXBOTTOM] = v2->y;
710 ld->bbox[BOXTOP] = v1->y;
711 }
712
713 /* calculate sound origin of line to be its midpoint */
714 //e6y: fix sound origin for large levels
715 // no need for comp_sound test, these are only used when comp_sound = 0
716 ld->soundorg.x = ld->bbox[BOXLEFT] / 2 + ld->bbox[BOXRIGHT] / 2;
717 ld->soundorg.y = ld->bbox[BOXTOP] / 2 + ld->bbox[BOXBOTTOM] / 2;
718
719 ld->iLineID=i; // proff 04/05/2000: needed for OpenGL
720 ld->sidenum[0] = SHORT(mld->sidenum[0]);
721 ld->sidenum[1] = SHORT(mld->sidenum[1]);
722
723 {
724 /* cph 2006/09/30 - fix sidedef errors right away.
725 * cph 2002/07/20 - these errors are fatal if not fixed, so apply them
726 * in compatibility mode - a desync is better than a crash! */
727 int j;
728
729 for (j=0; j < 2; j++)
730 {
731 if (ld->sidenum[j] != NO_INDEX && ld->sidenum[j] >= numsides) {
732 ld->sidenum[j] = NO_INDEX;
733 lprintf(LO_WARN, "P_LoadLineDefs: linedef %d has out-of-range sidedef number\n",numlines-i-1);
734 }
735 }
736
737 // killough 11/98: fix common wad errors (missing sidedefs):
738
739 if (ld->sidenum[0] == NO_INDEX) {
740 ld->sidenum[0] = 0; // Substitute dummy sidedef for missing right side
741 // cph - print a warning about the bug
742 lprintf(LO_WARN, "P_LoadLineDefs: linedef %d missing first sidedef\n",numlines-i-1);
743 }
744
745 if ((ld->sidenum[1] == NO_INDEX) && (ld->flags & ML_TWOSIDED)) {
746 ld->flags &= ~ML_TWOSIDED; // Clear 2s flag for missing left side
747 // cph - print a warning about the bug
748 lprintf(LO_WARN, "P_LoadLineDefs: linedef %d has two-sided flag set, but no second sidedef\n",numlines-i-1);
749 }
750 }
751
752 // killough 4/4/98: support special sidedef interpretation below
753 if (ld->sidenum[0] != NO_INDEX && ld->special)
754 sides[*ld->sidenum].special = ld->special;
755 }
756
757 W_UnlockLumpNum(lump); // cph - release the lump
758}
759
760// killough 4/4/98: delay using sidedefs until they are loaded
761// killough 5/3/98: reformatted, cleaned up
762
763static void P_LoadLineDefs2(int lump)
764{
765 int i = numlines;
766 register line_t *ld = lines;
767 for (;i--;ld++)
768 {
769 ld->frontsector = sides[ld->sidenum[0]].sector; //e6y: Can't be NO_INDEX here
770 ld->backsector = ld->sidenum[1]!=NO_INDEX ? sides[ld->sidenum[1]].sector : 0;
771 switch (ld->special)
772 { // killough 4/11/98: handle special types
773 int lump, j;
774
775 case 260: // killough 4/11/98: translucent 2s textures
776 lump = sides[*ld->sidenum].special; // translucency from sidedef
777 if (!ld->tag) // if tag==0,
778 ld->tranlump = lump; // affect this linedef only
779 else
780 for (j=0;j<numlines;j++) // if tag!=0,
781 if (lines[j].tag == ld->tag) // affect all matching linedefs
782 lines[j].tranlump = lump;
783 break;
784 }
785 }
786}
787
788//
789// P_LoadSideDefs
790//
791// killough 4/4/98: split into two functions
792
793static void P_LoadSideDefs (int lump)
794{
795 numsides = W_LumpLength(lump) / sizeof(mapsidedef_t);
796 sides = Z_Calloc(numsides,sizeof(side_t),PU_LEVEL,0);
797}
798
799// killough 4/4/98: delay using texture names until
800// after linedefs are loaded, to allow overloading.
801// killough 5/3/98: reformatted, cleaned up
802
803static void P_LoadSideDefs2(int lump)
804{
805 const byte *data = W_CacheLumpNum(lump); // cph - const*, wad lump handling updated
806 int i;
807
808 for (i=0; i<numsides; i++)
809 {
810 register const mapsidedef_t *msd = (const mapsidedef_t *) data + i;
811 register side_t *sd = sides + i;
812 register sector_t *sec;
813
814 sd->textureoffset = SHORT(msd->textureoffset)<<FRACBITS;
815 sd->rowoffset = SHORT(msd->rowoffset)<<FRACBITS;
816
817 { /* cph 2006/09/30 - catch out-of-range sector numbers; use sector 0 instead */
818 unsigned short sector_num = SHORT(msd->sector);
819 if (sector_num >= numsectors) {
820 lprintf(LO_WARN,"P_LoadSideDefs2: sidedef %i has out-of-range sector num %u\n", i, sector_num);
821 sector_num = 0;
822 }
823 sd->sector = sec = &sectors[sector_num];
824 }
825
826 // killough 4/4/98: allow sidedef texture names to be overloaded
827 // killough 4/11/98: refined to allow colormaps to work as wall
828 // textures if invalid as colormaps but valid as textures.
829 switch (sd->special)
830 {
831 case 242: // variable colormap via 242 linedef
832 sd->bottomtexture =
833 (sec->bottommap = R_ColormapNumForName(msd->bottomtexture)) < 0 ?
834 sec->bottommap = 0, R_TextureNumForName(msd->bottomtexture): 0 ;
835 sd->midtexture =
836 (sec->midmap = R_ColormapNumForName(msd->midtexture)) < 0 ?
837 sec->midmap = 0, R_TextureNumForName(msd->midtexture) : 0 ;
838 sd->toptexture =
839 (sec->topmap = R_ColormapNumForName(msd->toptexture)) < 0 ?
840 sec->topmap = 0, R_TextureNumForName(msd->toptexture) : 0 ;
841 break;
842
843 case 260: // killough 4/11/98: apply translucency to 2s normal texture
844 sd->midtexture = strncasecmp("TRANMAP", msd->midtexture, 8) ?
845 (sd->special = W_CheckNumForName(msd->midtexture)) < 0 ||
846 W_LumpLength(sd->special) != 65536 ?
847 sd->special=0, R_TextureNumForName(msd->midtexture) :
848 (sd->special++, 0) : (sd->special=0);
849 sd->toptexture = R_TextureNumForName(msd->toptexture);
850 sd->bottomtexture = R_TextureNumForName(msd->bottomtexture);
851 break;
852
853 default: // normal cases
854 sd->midtexture = R_SafeTextureNumForName(msd->midtexture, i);
855 sd->toptexture = R_SafeTextureNumForName(msd->toptexture, i);
856 sd->bottomtexture = R_SafeTextureNumForName(msd->bottomtexture, i);
857 break;
858 }
859 }
860
861 W_UnlockLumpNum(lump); // cph - release the lump
862}
863
864//
865// jff 10/6/98
866// New code added to speed up calculation of internal blockmap
867// Algorithm is order of nlines*(ncols+nrows) not nlines*ncols*nrows
868//
869
870#define blkshift 7 /* places to shift rel position for cell num */
871#define blkmask ((1<<blkshift)-1)/* mask for rel position within cell */
872#define blkmargin 0 /* size guardband around map used */
873 // jff 10/8/98 use guardband>0
874 // jff 10/12/98 0 ok with + 1 in rows,cols
875
876typedef struct linelist_t // type used to list lines in each block
877{
878 long num;
879 struct linelist_t *next;
880} linelist_t;
881
882//
883// Subroutine to add a line number to a block list
884// It simply returns if the line is already in the block
885//
886
887static void AddBlockLine
888(
889 linelist_t **lists,
890 int *count,
891 int *done,
892 int blockno,
893 long lineno
894)
895{
896 linelist_t *l;
897
898 if (done[blockno])
899 return;
900
901 l = malloc(sizeof(linelist_t));
902 l->num = lineno;
903 l->next = lists[blockno];
904 lists[blockno] = l;
905 count[blockno]++;
906 done[blockno] = 1;
907}
908
909//
910// Actually construct the blockmap lump from the level data
911//
912// This finds the intersection of each linedef with the column and
913// row lines at the left and bottom of each blockmap cell. It then
914// adds the line to all block lists touching the intersection.
915//
916
917static void P_CreateBlockMap(void)
918{
919 int xorg,yorg; // blockmap origin (lower left)
920 int nrows,ncols; // blockmap dimensions
921 linelist_t **blocklists=NULL; // array of pointers to lists of lines
922 int *blockcount=NULL; // array of counters of line lists
923 int *blockdone=NULL; // array keeping track of blocks/line
924 int NBlocks; // number of cells = nrows*ncols
925 long linetotal=0; // total length of all blocklists
926 int i,j;
927 int map_minx=INT_MAX; // init for map limits search
928 int map_miny=INT_MAX;
929 int map_maxx=INT_MIN;
930 int map_maxy=INT_MIN;
931
932 // scan for map limits, which the blockmap must enclose
933
934 for (i=0;i<numvertexes;i++)
935 {
936 fixed_t t;
937
938 if ((t=vertexes[i].x) < map_minx)
939 map_minx = t;
940 else if (t > map_maxx)
941 map_maxx = t;
942 if ((t=vertexes[i].y) < map_miny)
943 map_miny = t;
944 else if (t > map_maxy)
945 map_maxy = t;
946 }
947 map_minx >>= FRACBITS; // work in map coords, not fixed_t
948 map_maxx >>= FRACBITS;
949 map_miny >>= FRACBITS;
950 map_maxy >>= FRACBITS;
951
952 // set up blockmap area to enclose level plus margin
953
954 xorg = map_minx-blkmargin;
955 yorg = map_miny-blkmargin;
956 ncols = (map_maxx+blkmargin-xorg+1+blkmask)>>blkshift; //jff 10/12/98
957 nrows = (map_maxy+blkmargin-yorg+1+blkmask)>>blkshift; //+1 needed for
958 NBlocks = ncols*nrows; //map exactly 1 cell
959
960 // create the array of pointers on NBlocks to blocklists
961 // also create an array of linelist counts on NBlocks
962 // finally make an array in which we can mark blocks done per line
963
964 // CPhipps - calloc's
965 blocklists = calloc(NBlocks,sizeof(linelist_t *));
966 blockcount = calloc(NBlocks,sizeof(int));
967 blockdone = malloc(NBlocks*sizeof(int));
968
969 // initialize each blocklist, and enter the trailing -1 in all blocklists
970 // note the linked list of lines grows backwards
971
972 for (i=0;i<NBlocks;i++)
973 {
974 blocklists[i] = malloc(sizeof(linelist_t));
975 blocklists[i]->num = -1;
976 blocklists[i]->next = NULL;
977 blockcount[i]++;
978 }
979
980 // For each linedef in the wad, determine all blockmap blocks it touches,
981 // and add the linedef number to the blocklists for those blocks
982
983 for (i=0;i<numlines;i++)
984 {
985 int x1 = lines[i].v1->x>>FRACBITS; // lines[i] map coords
986 int y1 = lines[i].v1->y>>FRACBITS;
987 int x2 = lines[i].v2->x>>FRACBITS;
988 int y2 = lines[i].v2->y>>FRACBITS;
989 int dx = x2-x1;
990 int dy = y2-y1;
991 int vert = !dx; // lines[i] slopetype
992 int horiz = !dy;
993 int spos = (dx^dy) > 0;
994 int sneg = (dx^dy) < 0;
995 int bx,by; // block cell coords
996 int minx = x1>x2? x2 : x1; // extremal lines[i] coords
997 int maxx = x1>x2? x1 : x2;
998 int miny = y1>y2? y2 : y1;
999 int maxy = y1>y2? y1 : y2;
1000
1001 // no blocks done for this linedef yet
1002
1003 memset(blockdone,0,NBlocks*sizeof(int));
1004
1005 // The line always belongs to the blocks containing its endpoints
1006
1007 bx = (x1-xorg)>>blkshift;
1008 by = (y1-yorg)>>blkshift;
1009 AddBlockLine(blocklists,blockcount,blockdone,by*ncols+bx,i);
1010 bx = (x2-xorg)>>blkshift;
1011 by = (y2-yorg)>>blkshift;
1012 AddBlockLine(blocklists,blockcount,blockdone,by*ncols+bx,i);
1013
1014
1015 // For each column, see where the line along its left edge, which
1016 // it contains, intersects the Linedef i. Add i to each corresponding
1017 // blocklist.
1018
1019 if (!vert) // don't interesect vertical lines with columns
1020 {
1021 for (j=0;j<ncols;j++)
1022 {
1023 // intersection of Linedef with x=xorg+(j<<blkshift)
1024 // (y-y1)*dx = dy*(x-x1)
1025 // y = dy*(x-x1)+y1*dx;
1026
1027 int x = xorg+(j<<blkshift); // (x,y) is intersection
1028 int y = (dy*(x-x1))/dx+y1;
1029 int yb = (y-yorg)>>blkshift; // block row number
1030 int yp = (y-yorg)&blkmask; // y position within block
1031
1032 if (yb<0 || yb>nrows-1) // outside blockmap, continue
1033 continue;
1034
1035 if (x<minx || x>maxx) // line doesn't touch column
1036 continue;
1037
1038 // The cell that contains the intersection point is always added
1039
1040 AddBlockLine(blocklists,blockcount,blockdone,ncols*yb+j,i);
1041
1042 // if the intersection is at a corner it depends on the slope
1043 // (and whether the line extends past the intersection) which
1044 // blocks are hit
1045
1046 if (yp==0) // intersection at a corner
1047 {
1048 if (sneg) // \ - blocks x,y-, x-,y
1049 {
1050 if (yb>0 && miny<y)
1051 AddBlockLine(blocklists,blockcount,blockdone,ncols*(yb-1)+j,i);
1052 if (j>0 && minx<x)
1053 AddBlockLine(blocklists,blockcount,blockdone,ncols*yb+j-1,i);
1054 }
1055 else if (spos) // / - block x-,y-
1056 {
1057 if (yb>0 && j>0 && minx<x)
1058 AddBlockLine(blocklists,blockcount,blockdone,ncols*(yb-1)+j-1,i);
1059 }
1060 else if (horiz) // - - block x-,y
1061 {
1062 if (j>0 && minx<x)
1063 AddBlockLine(blocklists,blockcount,blockdone,ncols*yb+j-1,i);
1064 }
1065 }
1066 else if (j>0 && minx<x) // else not at corner: x-,y
1067 AddBlockLine(blocklists,blockcount,blockdone,ncols*yb+j-1,i);
1068 }
1069 }
1070
1071 // For each row, see where the line along its bottom edge, which
1072 // it contains, intersects the Linedef i. Add i to all the corresponding
1073 // blocklists.
1074
1075 if (!horiz)
1076 {
1077 for (j=0;j<nrows;j++)
1078 {
1079 // intersection of Linedef with y=yorg+(j<<blkshift)
1080 // (x,y) on Linedef i satisfies: (y-y1)*dx = dy*(x-x1)
1081 // x = dx*(y-y1)/dy+x1;
1082
1083 int y = yorg+(j<<blkshift); // (x,y) is intersection
1084 int x = (dx*(y-y1))/dy+x1;
1085 int xb = (x-xorg)>>blkshift; // block column number
1086 int xp = (x-xorg)&blkmask; // x position within block
1087
1088 if (xb<0 || xb>ncols-1) // outside blockmap, continue
1089 continue;
1090
1091 if (y<miny || y>maxy) // line doesn't touch row
1092 continue;
1093
1094 // The cell that contains the intersection point is always added
1095
1096 AddBlockLine(blocklists,blockcount,blockdone,ncols*j+xb,i);
1097
1098 // if the intersection is at a corner it depends on the slope
1099 // (and whether the line extends past the intersection) which
1100 // blocks are hit
1101
1102 if (xp==0) // intersection at a corner
1103 {
1104 if (sneg) // \ - blocks x,y-, x-,y
1105 {
1106 if (j>0 && miny<y)
1107 AddBlockLine(blocklists,blockcount,blockdone,ncols*(j-1)+xb,i);
1108 if (xb>0 && minx<x)
1109 AddBlockLine(blocklists,blockcount,blockdone,ncols*j+xb-1,i);
1110 }
1111 else if (vert) // | - block x,y-
1112 {
1113 if (j>0 && miny<y)
1114 AddBlockLine(blocklists,blockcount,blockdone,ncols*(j-1)+xb,i);
1115 }
1116 else if (spos) // / - block x-,y-
1117 {
1118 if (xb>0 && j>0 && miny<y)
1119 AddBlockLine(blocklists,blockcount,blockdone,ncols*(j-1)+xb-1,i);
1120 }
1121 }
1122 else if (j>0 && miny<y) // else not on a corner: x,y-
1123 AddBlockLine(blocklists,blockcount,blockdone,ncols*(j-1)+xb,i);
1124 }
1125 }
1126 }
1127
1128 // Add initial 0 to all blocklists
1129 // count the total number of lines (and 0's and -1's)
1130
1131 memset(blockdone,0,NBlocks*sizeof(int));
1132 for (i=0,linetotal=0;i<NBlocks;i++)
1133 {
1134 AddBlockLine(blocklists,blockcount,blockdone,i,0);
1135 linetotal += blockcount[i];
1136 }
1137
1138 // Create the blockmap lump
1139
1140 blockmaplump = Z_Malloc(sizeof(*blockmaplump) * (4+NBlocks+linetotal),
1141 PU_LEVEL, 0);
1142 // blockmap header
1143
1144 blockmaplump[0] = bmaporgx = xorg << FRACBITS;
1145 blockmaplump[1] = bmaporgy = yorg << FRACBITS;
1146 blockmaplump[2] = bmapwidth = ncols;
1147 blockmaplump[3] = bmapheight = nrows;
1148
1149 // offsets to lists and block lists
1150
1151 for (i=0;i<NBlocks;i++)
1152 {
1153 linelist_t *bl = blocklists[i];
1154 long offs = blockmaplump[4+i] = // set offset to block's list
1155 (i? blockmaplump[4+i-1] : 4+NBlocks) + (i? blockcount[i-1] : 0);
1156
1157 // add the lines in each block's list to the blockmaplump
1158 // delete each list node as we go
1159
1160 while (bl)
1161 {
1162 linelist_t *tmp = bl->next;
1163 blockmaplump[offs++] = bl->num;
1164 free(bl);
1165 bl = tmp;
1166 }
1167 }
1168
1169 // free all temporary storage
1170
1171 free (blocklists);
1172 free (blockcount);
1173 free (blockdone);
1174}
1175
1176// jff 10/6/98
1177// End new code added to speed up calculation of internal blockmap
1178
1179//
1180// P_LoadBlockMap
1181//
1182// killough 3/1/98: substantially modified to work
1183// towards removing blockmap limit (a wad limitation)
1184//
1185// killough 3/30/98: Rewritten to remove blockmap limit,
1186// though current algorithm is brute-force and unoptimal.
1187//
1188
1189static void P_LoadBlockMap (int lump)
1190{
1191 long count;
1192
1193 if (M_CheckParm("-blockmap") || W_LumpLength(lump)<8 || (count = W_LumpLength(lump)/2) >= 0x10000) //e6y
1194 P_CreateBlockMap();
1195 else
1196 {
1197 long i;
1198 // cph - const*, wad lump handling updated
1199 const short *wadblockmaplump = W_CacheLumpNum(lump);
1200 blockmaplump = Z_Malloc(sizeof(*blockmaplump) * count, PU_LEVEL, 0);
1201
1202 // killough 3/1/98: Expand wad blockmap into larger internal one,
1203 // by treating all offsets except -1 as unsigned and zero-extending
1204 // them. This potentially doubles the size of blockmaps allowed,
1205 // because Doom originally considered the offsets as always signed.
1206
1207 blockmaplump[0] = SHORT(wadblockmaplump[0]);
1208 blockmaplump[1] = SHORT(wadblockmaplump[1]);
1209 blockmaplump[2] = (long)(SHORT(wadblockmaplump[2])) & 0xffff;
1210 blockmaplump[3] = (long)(SHORT(wadblockmaplump[3])) & 0xffff;
1211
1212 for (i=4 ; i<count ; i++)
1213 {
1214 short t = SHORT(wadblockmaplump[i]); // killough 3/1/98
1215 blockmaplump[i] = t == -1 ? -1l : (long) t & 0xffff;
1216 }
1217
1218 W_UnlockLumpNum(lump); // cph - unlock the lump
1219
1220 bmaporgx = blockmaplump[0]<<FRACBITS;
1221 bmaporgy = blockmaplump[1]<<FRACBITS;
1222 bmapwidth = blockmaplump[2];
1223 bmapheight = blockmaplump[3];
1224 }
1225
1226 // clear out mobj chains - CPhipps - use calloc
1227 blocklinks = Z_Calloc (bmapwidth*bmapheight,sizeof(*blocklinks),PU_LEVEL,0);
1228 blockmap = blockmaplump+4;
1229}
1230
1231//
1232// P_LoadReject - load the reject table, padding it if it is too short
1233// totallines must be the number returned by P_GroupLines()
1234// an underflow will be padded with zeroes, or a doom.exe z_zone header
1235//
1236// this function incorporates e6y's RejectOverrunAddInt code:
1237// e6y: REJECT overrun emulation code
1238// It's emulated successfully if the size of overflow no more than 16 bytes.
1239// No more desync on teeth-32.wad\teeth-32.lmp.
1240// http://www.doomworld.com/vb/showthread.php?s=&threadid=35214
1241
1242static void P_LoadReject(int lumpnum, int totallines)
1243{
1244 unsigned int length, required;
1245 byte *newreject;
1246
1247 // dump any old cached reject lump, then cache the new one
1248 if (rejectlump != -1)
1249 W_UnlockLumpNum(rejectlump);
1250 rejectlump = lumpnum + ML_REJECT;
1251 rejectmatrix = W_CacheLumpNum(rejectlump);
1252
1253 required = (numsectors * numsectors + 7) / 8;
1254 length = W_LumpLength(rejectlump);
1255
1256 if (length >= required)
1257 return; // nothing to do
1258
1259 // allocate a new block and copy the reject table into it; zero the rest
1260 // PU_LEVEL => will be freed on level exit
1261 newreject = Z_Malloc(required, PU_LEVEL, NULL);
1262 rejectmatrix = (const byte *)memmove(newreject, rejectmatrix, length);
1263 memset(newreject + length, 0, required - length);
1264 // unlock the original lump, it is no longer needed
1265 W_UnlockLumpNum(rejectlump);
1266 rejectlump = -1;
1267
1268 if (demo_compatibility)
1269 {
1270 // merged in RejectOverrunAddInt(), and the 4 calls to it, here
1271 unsigned int rejectpad[4] = {
1272 0, // size, will be filled in using totallines
1273 0, // part of the header of a doom.exe z_zone block
1274 50, // DOOM_CONST_PU_LEVEL
1275 0x1d4a11 // DOOM_CONST_ZONEID
1276 };
1277 unsigned int i, pad = 0, *src = rejectpad;
1278 byte *dest = newreject + length;
1279
1280 rejectpad[0] = ((totallines*4+3)&~3)+24; // doom.exe zone header size
1281
1282 // copy at most 16 bytes from rejectpad
1283 // emulating a 32-bit, little-endian architecture (can't memmove)
1284 for (i = 0; i < required - length && i < 16; i++) { // 16 hard-coded
1285 if (!(i&3)) // get the next 4 bytes to copy when i=0,4,8,12
1286 pad = *src++;
1287 *dest++ = pad & 0xff; // store lowest-significant byte
1288 pad >>= 8; // rotate the next byte down
1289 }
1290 }
1291 lprintf(LO_WARN, "P_LoadReject: REJECT too short (%u<%u) - padded\n",
1292 length, required);
1293}
1294
1295//
1296// P_GroupLines
1297// Builds sector line lists and subsector sector numbers.
1298// Finds block bounding boxes for sectors.
1299//
1300// killough 5/3/98: reformatted, cleaned up
1301// cph 18/8/99: rewritten to avoid O(numlines * numsectors) section
1302// It makes things more complicated, but saves seconds on big levels
1303// figgi 09/18/00 -- adapted for gl-nodes
1304
1305// cph - convenient sub-function
1306static void P_AddLineToSector(line_t* li, sector_t* sector)
1307{
1308 fixed_t *bbox = (void*)sector->blockbox;
1309
1310 sector->lines[sector->linecount++] = li;
1311 M_AddToBox (bbox, li->v1->x, li->v1->y);
1312 M_AddToBox (bbox, li->v2->x, li->v2->y);
1313}
1314
1315// modified to return totallines (needed by P_LoadReject)
1316static int P_GroupLines (void)
1317{
1318 register line_t *li;
1319 register sector_t *sector;
1320 int i,j, total = numlines;
1321
1322 // figgi
1323 for (i=0 ; i<numsubsectors ; i++)
1324 {
1325 seg_t *seg = &segs[subsectors[i].firstline];
1326 subsectors[i].sector = NULL;
1327 for(j=0; j<subsectors[i].numlines; j++)
1328 {
1329 if(seg->sidedef)
1330 {
1331 subsectors[i].sector = seg->sidedef->sector;
1332 break;
1333 }
1334 seg++;
1335 }
1336 if(subsectors[i].sector == NULL)
1337 I_Error("P_GroupLines: Subsector a part of no sector!\n");
1338 }
1339
1340 // count number of lines in each sector
1341 for (i=0,li=lines; i<numlines; i++, li++)
1342 {
1343 li->frontsector->linecount++;
1344 if (li->backsector && li->backsector != li->frontsector)
1345 {
1346 li->backsector->linecount++;
1347 total++;
1348 }
1349 }
1350
1351 { // allocate line tables for each sector
1352 line_t **linebuffer = Z_Malloc(total*sizeof(line_t *), PU_LEVEL, 0);
1353
1354 // e6y: REJECT overrun emulation code
1355 // moved to P_LoadReject
1356
1357 for (i=0, sector = sectors; i<numsectors; i++, sector++)
1358 {
1359 sector->lines = linebuffer;
1360 linebuffer += sector->linecount;
1361 sector->linecount = 0;
1362 M_ClearBox(sector->blockbox);
1363 }
1364 }
1365
1366 // Enter those lines
1367 for (i=0,li=lines; i<numlines; i++, li++)
1368 {
1369 P_AddLineToSector(li, li->frontsector);
1370 if (li->backsector && li->backsector != li->frontsector)
1371 P_AddLineToSector(li, li->backsector);
1372 }
1373
1374 for (i=0, sector = sectors; i<numsectors; i++, sector++)
1375 {
1376 fixed_t *bbox = (void*)sector->blockbox; // cph - For convenience, so
1377 // I can sue the old code unchanged
1378 int block;
1379
1380 // set the degenmobj_t to the middle of the bounding box
1381 if (comp[comp_sound])
1382 {
1383 sector->soundorg.x = (bbox[BOXRIGHT]+bbox[BOXLEFT])/2;
1384 sector->soundorg.y = (bbox[BOXTOP]+bbox[BOXBOTTOM])/2;
1385 }
1386 else
1387 {
1388 //e6y: fix sound origin for large levels
1389 sector->soundorg.x = bbox[BOXRIGHT]/2+bbox[BOXLEFT]/2;
1390 sector->soundorg.y = bbox[BOXTOP]/2+bbox[BOXBOTTOM]/2;
1391 }
1392
1393 // adjust bounding box to map blocks
1394 block = (bbox[BOXTOP]-bmaporgy+MAXRADIUS)>>MAPBLOCKSHIFT;
1395 block = block >= bmapheight ? bmapheight-1 : block;
1396 sector->blockbox[BOXTOP]=block;
1397
1398 block = (bbox[BOXBOTTOM]-bmaporgy-MAXRADIUS)>>MAPBLOCKSHIFT;
1399 block = block < 0 ? 0 : block;
1400 sector->blockbox[BOXBOTTOM]=block;
1401
1402 block = (bbox[BOXRIGHT]-bmaporgx+MAXRADIUS)>>MAPBLOCKSHIFT;
1403 block = block >= bmapwidth ? bmapwidth-1 : block;
1404 sector->blockbox[BOXRIGHT]=block;
1405
1406 block = (bbox[BOXLEFT]-bmaporgx-MAXRADIUS)>>MAPBLOCKSHIFT;
1407 block = block < 0 ? 0 : block;
1408 sector->blockbox[BOXLEFT]=block;
1409 }
1410
1411 return total; // this value is needed by the reject overrun emulation code
1412}
1413
1414//
1415// killough 10/98
1416//
1417// Remove slime trails.
1418//
1419// Slime trails are inherent to Doom's coordinate system -- i.e. there is
1420// nothing that a node builder can do to prevent slime trails ALL of the time,
1421// because it's a product of the integer coodinate system, and just because
1422// two lines pass through exact integer coordinates, doesn't necessarily mean
1423// that they will intersect at integer coordinates. Thus we must allow for
1424// fractional coordinates if we are to be able to split segs with node lines,
1425// as a node builder must do when creating a BSP tree.
1426//
1427// A wad file does not allow fractional coordinates, so node builders are out
1428// of luck except that they can try to limit the number of splits (they might
1429// also be able to detect the degree of roundoff error and try to avoid splits
1430// with a high degree of roundoff error). But we can use fractional coordinates
1431// here, inside the engine. It's like the difference between square inches and
1432// square miles, in terms of granularity.
1433//
1434// For each vertex of every seg, check to see whether it's also a vertex of
1435// the linedef associated with the seg (i.e, it's an endpoint). If it's not
1436// an endpoint, and it wasn't already moved, move the vertex towards the
1437// linedef by projecting it using the law of cosines. Formula:
1438//
1439// 2 2 2 2
1440// dx x0 + dy x1 + dx dy (y0 - y1) dy y0 + dx y1 + dx dy (x0 - x1)
1441// {---------------------------------, ---------------------------------}
1442// 2 2 2 2
1443// dx + dy dx + dy
1444//
1445// (x0,y0) is the vertex being moved, and (x1,y1)-(x1+dx,y1+dy) is the
1446// reference linedef.
1447//
1448// Segs corresponding to orthogonal linedefs (exactly vertical or horizontal
1449// linedefs), which comprise at least half of all linedefs in most wads, don't
1450// need to be considered, because they almost never contribute to slime trails
1451// (because then any roundoff error is parallel to the linedef, which doesn't
1452// cause slime). Skipping simple orthogonal lines lets the code finish quicker.
1453//
1454// Please note: This section of code is not interchangable with TeamTNT's
1455// code which attempts to fix the same problem.
1456//
1457// Firelines (TM) is a Rezistered Trademark of MBF Productions
1458//
1459
1460static void P_RemoveSlimeTrails(void) // killough 10/98
1461{
1462 byte *hit = calloc(1, numvertexes); // Hitlist for vertices
1463 int i;
1464 for (i=0; i<numsegs; i++) // Go through each seg
1465 {
1466 const line_t *l;
1467
1468 if (segs[i].miniseg == true) //figgi -- skip minisegs
1469 return;
1470
1471 l = segs[i].linedef; // The parent linedef
1472 if (l->dx && l->dy) // We can ignore orthogonal lines
1473 {
1474 vertex_t *v = segs[i].v1;
1475 do
1476 if (!hit[v - vertexes]) // If we haven't processed vertex
1477 {
1478 hit[v - vertexes] = 1; // Mark this vertex as processed
1479 if (v != l->v1 && v != l->v2) // Exclude endpoints of linedefs
1480 { // Project the vertex back onto the parent linedef
1481 int_64_t dx2 = (l->dx >> FRACBITS) * (l->dx >> FRACBITS);
1482 int_64_t dy2 = (l->dy >> FRACBITS) * (l->dy >> FRACBITS);
1483 int_64_t dxy = (l->dx >> FRACBITS) * (l->dy >> FRACBITS);
1484 int_64_t s = dx2 + dy2;
1485 int x0 = v->x, y0 = v->y, x1 = l->v1->x, y1 = l->v1->y;
1486 v->x = (int)((dx2 * x0 + dy2 * x1 + dxy * (y0 - y1)) / s);
1487 v->y = (int)((dy2 * y0 + dx2 * y1 + dxy * (x0 - x1)) / s);
1488 }
1489 } // Obsfucated C contest entry: :)
1490 while ((v != segs[i].v2) && (v = segs[i].v2));
1491 }
1492 }
1493 free(hit);
1494}
1495
1496//
1497// P_SetupLevel
1498//
1499// killough 5/3/98: reformatted, cleaned up
1500
1501void P_SetupLevel(int episode, int map, int playermask, skill_t skill)
1502{
1503 int i;
1504 char lumpname[9];
1505 int lumpnum;
1506
1507 char gl_lumpname[9];
1508 int gl_lumpnum;
1509
1510 R_StopAllInterpolations();
1511
1512 totallive = totalkills = totalitems = totalsecret = wminfo.maxfrags = 0;
1513 wminfo.partime = 180;
1514
1515 for (i=0; i<MAXPLAYERS; i++)
1516 players[i].killcount = players[i].secretcount = players[i].itemcount = 0;
1517
1518 // Initial height of PointOfView will be set by player think.
1519 players[consoleplayer].viewz = 1;
1520
1521 // Make sure all sounds are stopped before Z_FreeTags.
1522 S_Start();
1523
1524 Z_FreeTags(PU_LEVEL, PU_PURGELEVEL-1);
1525 if (rejectlump != -1) { // cph - unlock the reject table
1526 W_UnlockLumpNum(rejectlump);
1527 rejectlump = -1;
1528 }
1529
1530#ifdef GL_DOOM
1531// proff 11/99: clean the memory from textures etc.
1532 gld_CleanMemory();
1533#endif
1534
1535 P_InitThinkers();
1536
1537 // if working with a devlopment map, reload it
1538 // W_Reload (); killough 1/31/98: W_Reload obsolete
1539
1540 // find map name
1541 if (gamemode == commercial)
1542 {
1543 sprintf(lumpname, "map%02d", map); // killough 1/24/98: simplify
1544 sprintf(gl_lumpname, "gl_map%02d", map); // figgi
1545 }
1546 else
1547 {
1548 sprintf(lumpname, "E%dM%d", episode, map); // killough 1/24/98: simplify
1549 sprintf(gl_lumpname, "GL_E%iM%i", episode, map); // figgi
1550 }
1551
1552 lumpnum = W_GetNumForName(lumpname);
1553 gl_lumpnum = W_CheckNumForName(gl_lumpname); // figgi
1554
1555 leveltime = 0; totallive = 0;
1556
1557 // note: most of this ordering is important
1558
1559 // killough 3/1/98: P_LoadBlockMap call moved down to below
1560 // killough 4/4/98: split load of sidedefs into two parts,
1561 // to allow texture names to be used in special linedefs
1562
1563 // refuse to load Hexen-format maps, avoid segfaults
1564 if ((i = lumpnum + ML_BLOCKMAP + 1) < numlumps
1565 && !strncasecmp(lumpinfo[i].name, "BEHAVIOR", 8))
1566 I_Error("P_SetupLevel: %s: Hexen format not supported", lumpname);
1567
1568#if 1
1569 // figgi 10/19/00 -- check for gl lumps and load them
1570 P_GetNodesVersion(lumpnum,gl_lumpnum);
1571
1572 if (nodesVersion > 0)
1573 P_LoadVertexes2 (lumpnum+ML_VERTEXES,gl_lumpnum+ML_GL_VERTS);
1574 else
1575 P_LoadVertexes (lumpnum+ML_VERTEXES);
1576 P_LoadSectors (lumpnum+ML_SECTORS);
1577 P_LoadSideDefs (lumpnum+ML_SIDEDEFS);
1578 P_LoadLineDefs (lumpnum+ML_LINEDEFS);
1579 P_LoadSideDefs2 (lumpnum+ML_SIDEDEFS);
1580 P_LoadLineDefs2 (lumpnum+ML_LINEDEFS);
1581 P_LoadBlockMap (lumpnum+ML_BLOCKMAP);
1582
1583 if (nodesVersion > 0)
1584 {
1585 P_LoadSubsectors(gl_lumpnum + ML_GL_SSECT);
1586 P_LoadNodes(gl_lumpnum + ML_GL_NODES);
1587 P_LoadGLSegs(gl_lumpnum + ML_GL_SEGS);
1588 }
1589 else
1590 {
1591 P_LoadSubsectors(lumpnum + ML_SSECTORS);
1592 P_LoadNodes(lumpnum + ML_NODES);
1593 P_LoadSegs(lumpnum + ML_SEGS);
1594 }
1595
1596#else
1597
1598 P_LoadVertexes (lumpnum+ML_VERTEXES);
1599 P_LoadSectors (lumpnum+ML_SECTORS);
1600 P_LoadSideDefs (lumpnum+ML_SIDEDEFS); // killough 4/4/98
1601 P_LoadLineDefs (lumpnum+ML_LINEDEFS); // |
1602 P_LoadSideDefs2 (lumpnum+ML_SIDEDEFS); // |
1603 P_LoadLineDefs2 (lumpnum+ML_LINEDEFS); // killough 4/4/98
1604 P_LoadBlockMap (lumpnum+ML_BLOCKMAP); // killough 3/1/98
1605 P_LoadSubsectors(lumpnum+ML_SSECTORS);
1606 P_LoadNodes (lumpnum+ML_NODES);
1607 P_LoadSegs (lumpnum+ML_SEGS);
1608
1609#endif
1610
1611 // reject loading and underflow padding separated out into new function
1612 // P_GroupLines modified to return a number the underflow padding needs
1613 P_LoadReject(lumpnum, P_GroupLines());
1614
1615 // e6y
1616 // Correction of desync on dv04-423.lmp/dv.wad
1617 // http://www.doomworld.com/vb/showthread.php?s=&postid=627257#post627257
1618 if (compatibility_level>=lxdoom_1_compatibility || M_CheckParm("-force_remove_slime_trails") > 0)
1619 P_RemoveSlimeTrails(); // killough 10/98: remove slime trails from wad
1620
1621 // Note: you don't need to clear player queue slots --
1622 // a much simpler fix is in g_game.c -- killough 10/98
1623
1624 bodyqueslot = 0;
1625
1626 /* cph - reset all multiplayer starts */
1627 memset(playerstarts,0,sizeof(playerstarts));
1628 deathmatch_p = deathmatchstarts;
1629 for (i = 0; i < MAXPLAYERS; i++)
1630 players[i].mo = NULL;
1631
1632 P_MapStart();
1633
1634 P_LoadThings(lumpnum+ML_THINGS);
1635
1636 // if deathmatch, randomly spawn the active players
1637 if (deathmatch)
1638 {
1639 for (i=0; i<MAXPLAYERS; i++)
1640 if (playeringame[i])
1641 {
1642 players[i].mo = NULL; // not needed? - done before P_LoadThings
1643 G_DeathMatchSpawnPlayer(i);
1644 }
1645 }
1646 else // if !deathmatch, check all necessary player starts actually exist
1647 {
1648 for (i=0; i<MAXPLAYERS; i++)
1649 if (playeringame[i] && !players[i].mo)
1650 I_Error("P_SetupLevel: missing player %d start\n", i+1);
1651 }
1652
1653 // killough 3/26/98: Spawn icon landings:
1654 if (gamemode==commercial)
1655 P_SpawnBrainTargets();
1656
1657 // clear special respawning que
1658 iquehead = iquetail = 0;
1659
1660 // set up world state
1661 P_SpawnSpecials();
1662
1663 P_MapEnd();
1664
1665 // preload graphics
1666 if (precache)
1667 R_PrecacheLevel();
1668
1669#ifdef GL_DOOM
1670 if (V_GetMode() == VID_MODEGL)
1671 {
1672 // proff 11/99: calculate all OpenGL specific tables etc.
1673 gld_PreprocessLevel();
1674 }
1675#endif
1676
1677 R_SmoothPlaying_Reset(NULL); // e6y
1678}
1679
1680//
1681// P_Init
1682//
1683void P_Init (void)
1684{
1685 P_InitSwitchList();
1686 P_InitPicAnims();
1687 R_InitSprites(sprnames);
1688}