1 /* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
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
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
28 * Do all the WAD I/O, get map description,
29 * set up initial state and misc. LUTs.
31 *-----------------------------------------------------------------------------*/
52 #include "rockmacros.h"
54 // MAP related Lookup tables.
55 // Store VERTEXES, LINEDEFS, SIDEDEFS, etc.
68 subsector_t
*subsectors
;
80 ////////////////////////////////////////////////////////////////////////////////////////////
81 // figgi 08/21/00 -- constants and globals for glBsp support
82 #define gNd2 0x32644E67 // figgi -- suppport for new GL_VERT format v2.0
83 #define GL_VERT_OFFSET 4
85 int firstglvertex
= 0;
86 boolean usingGLNodes
= false;
87 boolean forceOldBsp
= false;
91 ML_GL_LABEL
=0, // A separator name, GL_ExMx or GL_MAPxx
92 ML_GL_VERTS
, // Extra Vertices
93 ML_GL_SEGS
, // Segs, from linedefs & minisegs
94 ML_GL_SSECT
, // SubSectors, list of segs
95 ML_GL_NODES
// GL BSP nodes
97 ////////////////////////////////////////////////////////////////////////////////////////////
101 // Created from axis aligned bounding box
102 // of the map, a rectangular array of
103 // blocks of size ...
104 // Used to speed up collision detection
105 // by spatial subdivision in 2D.
109 int bmapwidth
, bmapheight
; // size in mapblocks
111 // killough 3/1/98: remove blockmap limit internally:
112 long *blockmap
; // was short -- killough
114 // offsets in blockmap are from here
115 long *blockmaplump
; // was short -- killough
117 fixed_t bmaporgx
, bmaporgy
; // origin of block map
119 mobj_t
**blocklinks
; // for thing chains
123 // For fast sight rejection.
124 // Speeds up enemy AI by skipping detailed
125 // LineOf Sight calculation.
126 // Without the special effect, this could
127 // be used as a PVS lookup as well.
130 static int rejectlump
= -1;// cph - store reject lump num if cached
131 const byte
*rejectmatrix
; // cph - const*
133 // Maintain single and multi player starting spots.
135 // 1/11/98 killough: Remove limit on deathmatch starts
136 mapthing_t
*deathmatchstarts
; // killough
137 size_t num_deathmatchstarts
; // killough
139 mapthing_t
*deathmatch_p
;
140 mapthing_t playerstarts
[MAXPLAYERS
];
145 // killough 5/3/98: reformatted, cleaned up
147 static void P_LoadVertexes (int lump
)
149 const byte
*data
; // cph - const
152 // Determine number of lumps:
153 // total lump length / vertex record length.
154 numvertexes
= W_LumpLength(lump
) / sizeof(mapvertex_t
);
156 // Allocate zone memory for buffer.
157 vertexes
= Z_Malloc(numvertexes
*sizeof(vertex_t
),PU_LEVEL
,0);
159 // Load data into cache.
160 data
= W_CacheLumpNum(lump
); // cph - wad handling updated
162 // Copy and convert vertex coordinates,
163 // internal representation as fixed.
164 for (i
=0; i
<numvertexes
; i
++)
166 vertexes
[i
].x
= SHORT(((mapvertex_t
*) data
)[i
].x
)<<FRACBITS
;
167 vertexes
[i
].y
= SHORT(((mapvertex_t
*) data
)[i
].y
)<<FRACBITS
;
170 // Free buffer memory.
171 W_UnlockLumpNum(lump
);
177 // killough 5/3/98: reformatted, cleaned up
179 static void P_LoadSegs (int lump
)
182 const byte
*data
; // cph - const
184 numsegs
= W_LumpLength(lump
) / sizeof(mapseg_t
);
185 segs
= Z_Calloc(numsegs
,sizeof(seg_t
),PU_LEVEL
,0);
186 data
= W_CacheLumpNum(lump
); // cph - wad lump handling updated
188 for (i
=0; i
<numsegs
; i
++)
191 mapseg_t
*ml
= (mapseg_t
*) data
+ i
;
196 li
->v1
= &vertexes
[SHORT(ml
->v1
)];
197 li
->v2
= &vertexes
[SHORT(ml
->v2
)];
199 li
->miniseg
= false; // figgi -- there are no minisegs in classic BSP nodes
201 li
->angle
= (SHORT(ml
->angle
))<<16;
202 li
->offset
=(SHORT(ml
->offset
))<<16;
203 linedef
= SHORT(ml
->linedef
);
204 ldef
= &lines
[linedef
];
206 side
= SHORT(ml
->side
);
207 li
->sidedef
= &sides
[ldef
->sidenum
[side
]];
208 li
->frontsector
= sides
[ldef
->sidenum
[side
]].sector
;
210 // killough 5/3/98: ignore 2s flag if second sidedef missing:
211 if (ldef
->flags
& ML_TWOSIDED
&& ldef
->sidenum
[side
^1]!=-1)
212 li
->backsector
= sides
[ldef
->sidenum
[side
^1]].sector
;
217 W_UnlockLumpNum(lump
); // cph - release the data
224 // killough 5/3/98: reformatted, cleaned up
226 static void P_LoadSubsectors (int lump
)
228 const byte
*data
; // cph - const*
231 numsubsectors
= W_LumpLength (lump
) / sizeof(mapsubsector_t
);
232 subsectors
= Z_Calloc(numsubsectors
,sizeof(subsector_t
),PU_LEVEL
,0);
233 data
= W_CacheLumpNum(lump
); // cph - wad lump handling updated
235 for (i
=0; i
<numsubsectors
; i
++)
237 subsectors
[i
].numlines
= (unsigned short)SHORT(((mapsubsector_t
*) data
)[i
].numsegs
);
238 subsectors
[i
].firstline
= (unsigned short)SHORT(((mapsubsector_t
*) data
)[i
].firstseg
);
241 W_UnlockLumpNum(lump
); // cph - release the data
247 // killough 5/3/98: reformatted, cleaned up
249 static void P_LoadSectors (int lump
)
251 const byte
*data
; // cph - const*
254 numsectors
= W_LumpLength (lump
) / sizeof(mapsector_t
);
255 sectors
= Z_Calloc (numsectors
,sizeof(sector_t
),PU_LEVEL
,0);
256 data
= W_CacheLumpNum (lump
); // cph - wad lump handling updated
258 for (i
=0; i
<numsectors
; i
++)
260 sector_t
*ss
= sectors
+ i
;
261 const mapsector_t
*ms
= (mapsector_t
*) data
+ i
;
263 ss
->floorheight
= SHORT(ms
->floorheight
)<<FRACBITS
;
264 ss
->ceilingheight
= SHORT(ms
->ceilingheight
)<<FRACBITS
;
265 ss
->floorpic
= R_FlatNumForName(ms
->floorpic
);
266 ss
->ceilingpic
= R_FlatNumForName(ms
->ceilingpic
);
267 ss
->lightlevel
= SHORT(ms
->lightlevel
);
268 ss
->special
= SHORT(ms
->special
);
269 ss
->oldspecial
= SHORT(ms
->special
);
270 ss
->tag
= SHORT(ms
->tag
);
271 ss
->thinglist
= NULL
;
272 ss
->touching_thinglist
= NULL
; // phares 3/14/98
274 ss
->nextsec
= -1; //jff 2/26/98 add fields to support locking out
275 ss
->prevsec
= -1; // stair retriggering until build completes
279 ss
->floor_yoffs
= 0; // floor and ceiling flats offsets
280 ss
->ceiling_xoffs
= 0;
281 ss
->ceiling_yoffs
= 0;
282 ss
->heightsec
= -1; // sector used to get floor and ceiling height
283 ss
->floorlightsec
= -1; // sector used to get floor lighting
284 // killough 3/7/98: end changes
286 // killough 4/11/98 sector used to get ceiling lighting:
287 ss
->ceilinglightsec
= -1;
289 // killough 4/4/98: colormaps:
290 ss
->bottommap
= ss
->midmap
= ss
->topmap
= 0;
292 // killough 10/98: sky textures coming from sidedefs:
296 W_UnlockLumpNum(lump
); // cph - release the data
303 // killough 5/3/98: reformatted, cleaned up
305 static void P_LoadNodes (int lump
)
307 const byte
*data
; // cph - const*
310 numnodes
= W_LumpLength (lump
) / sizeof(mapnode_t
);
311 nodes
= Z_Malloc (numnodes
*sizeof(node_t
),PU_LEVEL
,0);
312 data
= W_CacheLumpNum (lump
); // cph - wad lump handling updated
314 for (i
=0; i
<numnodes
; i
++)
316 node_t
*no
= nodes
+ i
;
317 mapnode_t
*mn
= (mapnode_t
*) data
+ i
;
320 no
->x
= SHORT(mn
->x
)<<FRACBITS
;
321 no
->y
= SHORT(mn
->y
)<<FRACBITS
;
322 no
->dx
= SHORT(mn
->dx
)<<FRACBITS
;
323 no
->dy
= SHORT(mn
->dy
)<<FRACBITS
;
325 for (j
=0 ; j
<2 ; j
++)
328 no
->children
[j
] = SHORT(mn
->children
[j
]);
329 for (k
=0 ; k
<4 ; k
++)
330 no
->bbox
[j
][k
] = SHORT(mn
->bbox
[j
][k
])<<FRACBITS
;
334 W_UnlockLumpNum(lump
); // cph - release the data
341 // killough 5/3/98: reformatted, cleaned up
343 static void P_LoadThings (int lump
)
345 mapthing_t tempthing
; // this needed to be added as the SHORT calls were overwriting eachother on reload
346 int i
, numthings
= W_LumpLength (lump
) / sizeof(mapthing_t
);
347 const byte
*data
= W_CacheLumpNum (lump
); // cph - wad lump handling updated, const*
349 for (i
=0; i
<numthings
; i
++)
351 mapthing_t
*mt
= (mapthing_t
*) data
+ i
;
353 // Do not spawn cool, new monsters if !commercial
354 if (gamemode
!= commercial
)
357 case 68: // Arachnotron
359 case 88: // Boss Brain
360 case 89: // Boss Shooter
361 case 69: // Hell Knight
363 case 71: // Pain Elemental
364 case 65: // Former Human Commando
370 // Do spawn all other stuff.
371 tempthing
.x
= SHORT(mt
->x
);
372 tempthing
.y
= SHORT(mt
->y
);
373 tempthing
.angle
= SHORT(mt
->angle
);
374 tempthing
.type
= SHORT(mt
->type
);
375 tempthing
.options
= SHORT(mt
->options
);
377 P_SpawnMapThing (&tempthing
);
380 W_UnlockLumpNum(lump
); // cph - release the data
385 // Also counts secret lines for intermissions.
388 // Does this mean secrets used to be linedef-based, rather than sector-based?
390 // killough 4/4/98: split into two functions, to allow sidedef overloading
392 // killough 5/3/98: reformatted, cleaned up
394 static void P_LoadLineDefs (int lump
)
396 const byte
*data
; // cph - const*
399 numlines
= W_LumpLength (lump
) / sizeof(maplinedef_t
);
400 lines
= Z_Calloc (numlines
,sizeof(line_t
),PU_LEVEL
,0);
401 data
= W_CacheLumpNum (lump
); // cph - wad lump handling updated
403 for (i
=0; i
<numlines
; i
++)
405 maplinedef_t
*mld
= (maplinedef_t
*) data
+ i
;
406 line_t
*ld
= lines
+i
;
409 ld
->flags
= SHORT(mld
->flags
);
410 ld
->special
= SHORT(mld
->special
);
411 ld
->tag
= SHORT(mld
->tag
);
412 v1
= ld
->v1
= &vertexes
[SHORT(mld
->v1
)];
413 v2
= ld
->v2
= &vertexes
[SHORT(mld
->v2
)];
414 ld
->dx
= v2
->x
- v1
->x
;
415 ld
->dy
= v2
->y
- v1
->y
;
417 ld
->tranlump
= -1; // killough 4/11/98: no translucency by default
419 ld
->slopetype
= !ld
->dx
? ST_VERTICAL
: !ld
->dy
? ST_HORIZONTAL
:
420 FixedDiv(ld
->dy
, ld
->dx
) > 0 ? ST_POSITIVE
: ST_NEGATIVE
;
424 ld
->bbox
[BOXLEFT
] = v1
->x
;
425 ld
->bbox
[BOXRIGHT
] = v2
->x
;
429 ld
->bbox
[BOXLEFT
] = v2
->x
;
430 ld
->bbox
[BOXRIGHT
] = v1
->x
;
435 ld
->bbox
[BOXBOTTOM
] = v1
->y
;
436 ld
->bbox
[BOXTOP
] = v2
->y
;
440 ld
->bbox
[BOXBOTTOM
] = v2
->y
;
441 ld
->bbox
[BOXTOP
] = v1
->y
;
444 ld
->sidenum
[0] = SHORT(mld
->sidenum
[0]);
445 ld
->sidenum
[1] = SHORT(mld
->sidenum
[1]);
447 // killough 4/4/98: support special sidedef interpretation below
448 if (ld
->sidenum
[0] != -1 && ld
->special
)
449 sides
[*ld
->sidenum
].special
= ld
->special
;
452 W_UnlockLumpNum(lump
); // cph - release the lump
455 // killough 4/4/98: delay using sidedefs until they are loaded
456 // killough 5/3/98: reformatted, cleaned up
458 static void P_LoadLineDefs2(int lump
)
462 register line_t
*ld
= lines
;
465 { // cph 2002/07/20 - these errors are fatal if not fixed, so apply them in compatibility mode - a desync is better than a crash!
466 // killough 11/98: fix common wad errors (missing sidedefs):
468 if (ld
->sidenum
[0] == -1) {
469 ld
->sidenum
[0] = 0; // Substitute dummy sidedef for missing right side
470 // cph - print a warning about the bug
471 printf("P_LoadSegs: linedef %d missing first sidedef\n",numlines
-i
);
474 if ((ld
->sidenum
[1] == -1) && (ld
->flags
& ML_TWOSIDED
)) {
475 ld
->flags
&= ~ML_TWOSIDED
; // Clear 2s flag for missing left side
476 // cph - print a warning about the bug
477 printf("P_LoadSegs: linedef %d has two-sided flag set, but no second sidedef\n",numlines
-i
);
481 ld
->frontsector
= ld
->sidenum
[0]!=-1 ? sides
[ld
->sidenum
[0]].sector
: 0;
482 ld
->backsector
= ld
->sidenum
[1]!=-1 ? sides
[ld
->sidenum
[1]].sector
: 0;
484 { // killough 4/11/98: handle special types
487 case 260: // killough 4/11/98: translucent 2s textures
488 lump
= sides
[*ld
->sidenum
].special
; // translucency from sidedef
489 if (!ld
->tag
) // if tag==0,
490 ld
->tranlump
= lump
; // affect this linedef only
492 for (j
=0;j
<numlines
;j
++) // if tag!=0,
493 if (lines
[j
].tag
== ld
->tag
) // affect all matching linedefs
494 lines
[j
].tranlump
= lump
;
503 // killough 4/4/98: split into two functions
505 static void P_LoadSideDefs (int lump
)
507 numsides
= W_LumpLength(lump
) / sizeof(mapsidedef_t
);
508 sides
= Z_Calloc(numsides
,sizeof(side_t
),PU_LEVEL
,0);
511 // killough 4/4/98: delay using texture names until
512 // after linedefs are loaded, to allow overloading.
513 // killough 5/3/98: reformatted, cleaned up
515 static void P_LoadSideDefs2(int lump
)
517 const byte
*data
= W_CacheLumpNum(lump
); // cph - const*, wad lump handling updated
520 for (i
=0; i
<numsides
; i
++)
522 register mapsidedef_t
*msd
= (mapsidedef_t
*) data
+ i
;
523 register side_t
*sd
= sides
+ i
;
524 register sector_t
*sec
;
526 sd
->textureoffset
= SHORT(msd
->textureoffset
)<<FRACBITS
;
527 sd
->rowoffset
= SHORT(msd
->rowoffset
)<<FRACBITS
;
529 // killough 4/4/98: allow sidedef texture names to be overloaded
530 // killough 4/11/98: refined to allow colormaps to work as wall
531 // textures if invalid as colormaps but valid as textures.
533 sd
->sector
= sec
= §ors
[SHORT(msd
->sector
)];
536 case 242: // variable colormap via 242 linedef
538 (sec
->bottommap
= R_ColormapNumForName(msd
->bottomtexture
)) < 0 ?
539 sec
->bottommap
= 0, R_TextureNumForName(msd
->bottomtexture
): 0 ;
541 (sec
->midmap
= R_ColormapNumForName(msd
->midtexture
)) < 0 ?
542 sec
->midmap
= 0, R_TextureNumForName(msd
->midtexture
) : 0 ;
544 (sec
->topmap
= R_ColormapNumForName(msd
->toptexture
)) < 0 ?
545 sec
->topmap
= 0, R_TextureNumForName(msd
->toptexture
) : 0 ;
548 case 260: // killough 4/11/98: apply translucency to 2s normal texture
549 sd
->midtexture
= strncasecmp("TRANMAP", msd
->midtexture
, 8) ?
550 (sd
->special
= W_CheckNumForName(msd
->midtexture
)) < 0 ||
551 W_LumpLength(sd
->special
) != 65536 ?
552 sd
->special
=0, R_TextureNumForName(msd
->midtexture
) :
553 (sd
->special
++, 0) : (sd
->special
=0);
554 sd
->toptexture
= R_TextureNumForName(msd
->toptexture
);
555 sd
->bottomtexture
= R_TextureNumForName(msd
->bottomtexture
);
558 default: // normal cases
559 sd
->midtexture
= R_TextureNumForName(msd
->midtexture
);
560 sd
->toptexture
= R_TextureNumForName(msd
->toptexture
);
561 sd
->bottomtexture
= R_TextureNumForName(msd
->bottomtexture
);
566 W_UnlockLumpNum(lump
); // cph - release the lump
571 // New code added to speed up calculation of internal blockmap
572 // Algorithm is order of nlines*(ncols+nrows) not nlines*ncols*nrows
575 #define blkshift 7 /* places to shift rel position for cell num */
576 #define blkmask ((1<<blkshift)-1)/* mask for rel position within cell */
577 #define blkmargin 0 /* size guardband around map used */
578 // jff 10/8/98 use guardband>0
579 // jff 10/12/98 0 ok with + 1 in rows,cols
581 typedef struct linelist_t
// type used to list lines in each block
584 struct linelist_t
*next
;
588 // Subroutine to add a line number to a block list
589 // It simply returns if the line is already in the block
592 static void AddBlockLine
606 l
= malloc(sizeof(linelist_t
));
608 l
->next
= lists
[blockno
];
615 // Actually construct the blockmap lump from the level data
617 // This finds the intersection of each linedef with the column and
618 // row lines at the left and bottom of each blockmap cell. It then
619 // adds the line to all block lists touching the intersection.
622 void P_CreateBlockMap()
624 int xorg
,yorg
; // blockmap origin (lower left)
625 int nrows
,ncols
; // blockmap dimensions
626 linelist_t
**blocklists
=NULL
; // array of pointers to lists of lines
627 int *blockcount
=NULL
; // array of counters of line lists
628 int *blockdone
=NULL
; // array keeping track of blocks/line
629 int NBlocks
; // number of cells = nrows*ncols
630 long linetotal
=0; // total length of all blocklists
632 int map_minx
=INT_MAX
; // init for map limits search
633 int map_miny
=INT_MAX
;
634 int map_maxx
=INT_MIN
;
635 int map_maxy
=INT_MIN
;
637 // scan for map limits, which the blockmap must enclose
639 for (i
=0;i
<numvertexes
;i
++)
643 if ((t
=vertexes
[i
].x
) < map_minx
)
645 else if (t
> map_maxx
)
647 if ((t
=vertexes
[i
].y
) < map_miny
)
649 else if (t
> map_maxy
)
652 map_minx
>>= FRACBITS
; // work in map coords, not fixed_t
653 map_maxx
>>= FRACBITS
;
654 map_miny
>>= FRACBITS
;
655 map_maxy
>>= FRACBITS
;
657 // set up blockmap area to enclose level plus margin
659 xorg
= map_minx
-blkmargin
;
660 yorg
= map_miny
-blkmargin
;
661 ncols
= (map_maxx
+blkmargin
-xorg
+1+blkmask
)>>blkshift
; //jff 10/12/98
662 nrows
= (map_maxy
+blkmargin
-yorg
+1+blkmask
)>>blkshift
; //+1 needed for
663 NBlocks
= ncols
*nrows
; //map exactly 1 cell
665 // create the array of pointers on NBlocks to blocklists
666 // also create an array of linelist counts on NBlocks
667 // finally make an array in which we can mark blocks done per line
669 // CPhipps - calloc's
670 blocklists
= calloc(NBlocks
,sizeof(linelist_t
*));
671 blockcount
= calloc(NBlocks
,sizeof(int));
672 blockdone
= malloc(NBlocks
*sizeof(int));
674 // initialize each blocklist, and enter the trailing -1 in all blocklists
675 // note the linked list of lines grows backwards
677 for (i
=0;i
<NBlocks
;i
++)
679 blocklists
[i
] = malloc(sizeof(linelist_t
));
680 blocklists
[i
]->num
= -1;
681 blocklists
[i
]->next
= NULL
;
685 // For each linedef in the wad, determine all blockmap blocks it touches,
686 // and add the linedef number to the blocklists for those blocks
688 for (i
=0;i
<numlines
;i
++)
690 int x1
= lines
[i
].v1
->x
>>FRACBITS
; // lines[i] map coords
691 int y1
= lines
[i
].v1
->y
>>FRACBITS
;
692 int x2
= lines
[i
].v2
->x
>>FRACBITS
;
693 int y2
= lines
[i
].v2
->y
>>FRACBITS
;
696 int vert
= !dx
; // lines[i] slopetype
698 int spos
= (dx
^dy
) > 0;
699 int sneg
= (dx
^dy
) < 0;
700 int bx
,by
; // block cell coords
701 int minx
= x1
>x2
? x2
: x1
; // extremal lines[i] coords
702 int maxx
= x1
>x2
? x1
: x2
;
703 int miny
= y1
>y2
? y2
: y1
;
704 int maxy
= y1
>y2
? y1
: y2
;
706 // no blocks done for this linedef yet
708 memset(blockdone
,0,NBlocks
*sizeof(int));
710 // The line always belongs to the blocks containing its endpoints
712 bx
= (x1
-xorg
)>>blkshift
;
713 by
= (y1
-yorg
)>>blkshift
;
714 AddBlockLine(blocklists
,blockcount
,blockdone
,by
*ncols
+bx
,i
);
715 bx
= (x2
-xorg
)>>blkshift
;
716 by
= (y2
-yorg
)>>blkshift
;
717 AddBlockLine(blocklists
,blockcount
,blockdone
,by
*ncols
+bx
,i
);
720 // For each column, see where the line along its left edge, which
721 // it contains, intersects the Linedef i. Add i to each corresponding
724 if (!vert
) // don't interesect vertical lines with columns
726 for (j
=0;j
<ncols
;j
++)
728 // intersection of Linedef with x=xorg+(j<<blkshift)
729 // (y-y1)*dx = dy*(x-x1)
730 // y = dy*(x-x1)+y1*dx;
732 int x
= xorg
+(j
<<blkshift
); // (x,y) is intersection
733 int y
= (dy
*(x
-x1
))/dx
+y1
;
734 int yb
= (y
-yorg
)>>blkshift
; // block row number
735 int yp
= (y
-yorg
)&blkmask
; // y position within block
737 if (yb
<0 || yb
>nrows
-1) // outside blockmap, continue
740 if (x
<minx
|| x
>maxx
) // line doesn't touch column
743 // The cell that contains the intersection point is always added
745 AddBlockLine(blocklists
,blockcount
,blockdone
,ncols
*yb
+j
,i
);
747 // if the intersection is at a corner it depends on the slope
748 // (and whether the line extends past the intersection) which
751 if (yp
==0) // intersection at a corner
753 if (sneg
) // \ - blocks x,y-, x-,y
756 AddBlockLine(blocklists
,blockcount
,blockdone
,ncols
*(yb
-1)+j
,i
);
758 AddBlockLine(blocklists
,blockcount
,blockdone
,ncols
*yb
+j
-1,i
);
760 else if (spos
) // / - block x-,y-
762 if (yb
>0 && j
>0 && minx
<x
)
763 AddBlockLine(blocklists
,blockcount
,blockdone
,ncols
*(yb
-1)+j
-1,i
);
765 else if (horiz
) // - - block x-,y
768 AddBlockLine(blocklists
,blockcount
,blockdone
,ncols
*yb
+j
-1,i
);
771 else if (j
>0 && minx
<x
) // else not at corner: x-,y
772 AddBlockLine(blocklists
,blockcount
,blockdone
,ncols
*yb
+j
-1,i
);
776 // For each row, see where the line along its bottom edge, which
777 // it contains, intersects the Linedef i. Add i to all the corresponding
782 for (j
=0;j
<nrows
;j
++)
784 // intersection of Linedef with y=yorg+(j<<blkshift)
785 // (x,y) on Linedef i satisfies: (y-y1)*dx = dy*(x-x1)
786 // x = dx*(y-y1)/dy+x1;
788 int y
= yorg
+(j
<<blkshift
); // (x,y) is intersection
789 int x
= (dx
*(y
-y1
))/dy
+x1
;
790 int xb
= (x
-xorg
)>>blkshift
; // block column number
791 int xp
= (x
-xorg
)&blkmask
; // x position within block
793 if (xb
<0 || xb
>ncols
-1) // outside blockmap, continue
796 if (y
<miny
|| y
>maxy
) // line doesn't touch row
799 // The cell that contains the intersection point is always added
801 AddBlockLine(blocklists
,blockcount
,blockdone
,ncols
*j
+xb
,i
);
803 // if the intersection is at a corner it depends on the slope
804 // (and whether the line extends past the intersection) which
807 if (xp
==0) // intersection at a corner
809 if (sneg
) // \ - blocks x,y-, x-,y
812 AddBlockLine(blocklists
,blockcount
,blockdone
,ncols
*(j
-1)+xb
,i
);
814 AddBlockLine(blocklists
,blockcount
,blockdone
,ncols
*j
+xb
-1,i
);
816 else if (vert
) // | - block x,y-
819 AddBlockLine(blocklists
,blockcount
,blockdone
,ncols
*(j
-1)+xb
,i
);
821 else if (spos
) // / - block x-,y-
823 if (xb
>0 && j
>0 && miny
<y
)
824 AddBlockLine(blocklists
,blockcount
,blockdone
,ncols
*(j
-1)+xb
-1,i
);
827 else if (j
>0 && miny
<y
) // else not on a corner: x,y-
828 AddBlockLine(blocklists
,blockcount
,blockdone
,ncols
*(j
-1)+xb
,i
);
833 // Add initial 0 to all blocklists
834 // count the total number of lines (and 0's and -1's)
836 memset(blockdone
,0,NBlocks
*sizeof(int));
837 for (i
=0,linetotal
=0;i
<NBlocks
;i
++)
839 AddBlockLine(blocklists
,blockcount
,blockdone
,i
,0);
840 linetotal
+= blockcount
[i
];
843 // Create the blockmap lump
845 blockmaplump
= Z_Malloc(sizeof(*blockmaplump
) * (4+NBlocks
+linetotal
),
849 blockmaplump
[0] = bmaporgx
= xorg
<< FRACBITS
;
850 blockmaplump
[1] = bmaporgy
= yorg
<< FRACBITS
;
851 blockmaplump
[2] = bmapwidth
= ncols
;
852 blockmaplump
[3] = bmapheight
= nrows
;
854 // offsets to lists and block lists
856 for (i
=0;i
<NBlocks
;i
++)
858 linelist_t
*bl
= blocklists
[i
];
859 long offs
= blockmaplump
[4+i
] = // set offset to block's list
860 (i
? blockmaplump
[4+i
-1] : 4+NBlocks
) + (i
? blockcount
[i
-1] : 0);
862 // add the lines in each block's list to the blockmaplump
863 // delete each list node as we go
867 linelist_t
*tmp
= bl
->next
;
868 blockmaplump
[offs
++] = bl
->num
;
874 // free all temporary storage
882 // End new code added to speed up calculation of internal blockmap
887 // killough 3/1/98: substantially modified to work
888 // towards removing blockmap limit (a wad limitation)
890 // killough 3/30/98: Rewritten to remove blockmap limit,
891 // though current algorithm is brute-force and unoptimal.
894 static void P_LoadBlockMap (int lump
)
898 if (M_CheckParm("-blockmap") || (count
= W_LumpLength(lump
)/2) >= 0x10000)
903 // cph - const*, wad lump handling updated
904 const short *wadblockmaplump
= W_CacheLumpNum(lump
);
905 blockmaplump
= Z_Malloc(sizeof(*blockmaplump
) * count
, PU_LEVEL
, 0);
907 // killough 3/1/98: Expand wad blockmap into larger internal one,
908 // by treating all offsets except -1 as unsigned and zero-extending
909 // them. This potentially doubles the size of blockmaps allowed,
910 // because Doom originally considered the offsets as always signed.
912 blockmaplump
[0] = SHORT(wadblockmaplump
[0]);
913 blockmaplump
[1] = SHORT(wadblockmaplump
[1]);
914 blockmaplump
[2] = (long)(SHORT(wadblockmaplump
[2])) & 0xffff;
915 blockmaplump
[3] = (long)(SHORT(wadblockmaplump
[3])) & 0xffff;
917 for (i
=4 ; i
<count
; i
++)
919 short t
= SHORT(wadblockmaplump
[i
]); // killough 3/1/98
920 blockmaplump
[i
] = t
== -1 ? -1l : (long) t
& 0xffff;
923 W_UnlockLumpNum(lump
); // cph - unlock the lump
925 bmaporgx
= blockmaplump
[0]<<FRACBITS
;
926 bmaporgy
= blockmaplump
[1]<<FRACBITS
;
927 bmapwidth
= blockmaplump
[2];
928 bmapheight
= blockmaplump
[3];
931 // clear out mobj chains - CPhipps - use calloc
932 blocklinks
= Z_Calloc (bmapwidth
*bmapheight
,sizeof(*blocklinks
),PU_LEVEL
,0);
933 blockmap
= blockmaplump
+4;
938 // Builds sector line lists and subsector sector numbers.
939 // Finds block bounding boxes for sectors.
941 // killough 5/3/98: reformatted, cleaned up
942 // cph 18/8/99: rewritten to avoid O(numlines * numsectors) section
943 // It makes things more complicated, but saves seconds on big levels
944 // figgi 09/18/00 -- adapted for gl-nodes
946 // cph - convenient sub-function
947 static void P_AddLineToSector(line_t
* li
, sector_t
* sector
)
949 fixed_t
*bbox
= (void*)sector
->blockbox
;
951 sector
->lines
[sector
->linecount
++] = li
;
952 M_AddToBox (bbox
, li
->v1
->x
, li
->v1
->y
);
953 M_AddToBox (bbox
, li
->v2
->x
, li
->v2
->y
);
956 void P_GroupLines (void)
959 register sector_t
*sector
;
960 int i
,j
, total
= numlines
;
963 for (i
=0 ; i
<numsubsectors
; i
++)
965 seg_t
*seg
= &segs
[subsectors
[i
].firstline
];
966 subsectors
[i
].sector
= NULL
;
967 for(j
=0; j
<subsectors
[i
].numlines
; j
++)
971 subsectors
[i
].sector
= seg
->sidedef
->sector
;
976 if(subsectors
[i
].sector
== NULL
)
977 I_Error("P_GroupLines: Subsector a part of no sector!\n");
980 // count number of lines in each sector
981 for (i
=0,li
=lines
; i
<numlines
; i
++, li
++)
983 li
->frontsector
->linecount
++;
984 if (li
->backsector
&& li
->backsector
!= li
->frontsector
)
986 li
->backsector
->linecount
++;
991 { // allocate line tables for each sector
992 line_t
**linebuffer
= Z_Malloc(total
*sizeof(line_t
*), PU_LEVEL
, 0);
994 for (i
=0, sector
= sectors
; i
<numsectors
; i
++, sector
++)
996 sector
->lines
= linebuffer
;
997 linebuffer
+= sector
->linecount
;
998 sector
->linecount
= 0;
999 M_ClearBox(sector
->blockbox
);
1003 // Enter those lines
1004 for (i
=0,li
=lines
; i
<numlines
; i
++, li
++)
1006 P_AddLineToSector(li
, li
->frontsector
);
1007 if (li
->backsector
&& li
->backsector
!= li
->frontsector
)
1008 P_AddLineToSector(li
, li
->backsector
);
1011 for (i
=0, sector
= sectors
; i
<numsectors
; i
++, sector
++)
1013 fixed_t
*bbox
= (void*)sector
->blockbox
; // cph - For convenience, so
1014 // I can sue the old code unchanged
1017 // set the degenmobj_t to the middle of the bounding box
1018 sector
->soundorg
.x
= (bbox
[BOXRIGHT
]+bbox
[BOXLEFT
])/2;
1019 sector
->soundorg
.y
= (bbox
[BOXTOP
]+bbox
[BOXBOTTOM
])/2;
1021 // adjust bounding box to map blocks
1022 block
= (bbox
[BOXTOP
]-bmaporgy
+MAXRADIUS
)>>MAPBLOCKSHIFT
;
1023 block
= block
>= bmapheight
? bmapheight
-1 : block
;
1024 sector
->blockbox
[BOXTOP
]=block
;
1026 block
= (bbox
[BOXBOTTOM
]-bmaporgy
-MAXRADIUS
)>>MAPBLOCKSHIFT
;
1027 block
= block
< 0 ? 0 : block
;
1028 sector
->blockbox
[BOXBOTTOM
]=block
;
1030 block
= (bbox
[BOXRIGHT
]-bmaporgx
+MAXRADIUS
)>>MAPBLOCKSHIFT
;
1031 block
= block
>= bmapwidth
? bmapwidth
-1 : block
;
1032 sector
->blockbox
[BOXRIGHT
]=block
;
1034 block
= (bbox
[BOXLEFT
]-bmaporgx
-MAXRADIUS
)>>MAPBLOCKSHIFT
;
1035 block
= block
< 0 ? 0 : block
;
1036 sector
->blockbox
[BOXLEFT
]=block
;
1044 // Remove slime trails.
1046 // Slime trails are inherent to Doom's coordinate system -- i.e. there is
1047 // nothing that a node builder can do to prevent slime trails ALL of the time,
1048 // because it's a product of the integer coodinate system, and just because
1049 // two lines pass through exact integer coordinates, doesn't necessarily mean
1050 // that they will intersect at integer coordinates. Thus we must allow for
1051 // fractional coordinates if we are to be able to split segs with node lines,
1052 // as a node builder must do when creating a BSP tree.
1054 // A wad file does not allow fractional coordinates, so node builders are out
1055 // of luck except that they can try to limit the number of splits (they might
1056 // also be able to detect the degree of roundoff error and try to avoid splits
1057 // with a high degree of roundoff error). But we can use fractional coordinates
1058 // here, inside the engine. It's like the difference between square inches and
1059 // square miles, in terms of granularity.
1061 // For each vertex of every seg, check to see whether it's also a vertex of
1062 // the linedef associated with the seg (i.e, it's an endpoint). If it's not
1063 // an endpoint, and it wasn't already moved, move the vertex towards the
1064 // linedef by projecting it using the law of cosines. Formula:
1067 // dx x0 + dy x1 + dx dy (y0 - y1) dy y0 + dx y1 + dx dy (x0 - x1)
1068 // {---------------------------------, ---------------------------------}
1072 // (x0,y0) is the vertex being moved, and (x1,y1)-(x1+dx,y1+dy) is the
1073 // reference linedef.
1075 // Segs corresponding to orthogonal linedefs (exactly vertical or horizontal
1076 // linedefs), which comprise at least half of all linedefs in most wads, don't
1077 // need to be considered, because they almost never contribute to slime trails
1078 // (because then any roundoff error is parallel to the linedef, which doesn't
1079 // cause slime). Skipping simple orthogonal lines lets the code finish quicker.
1081 // Please note: This section of code is not interchangable with TeamTNT's
1082 // code which attempts to fix the same problem.
1084 // Firelines (TM) is a Rezistered Trademark of MBF Productions
1087 void P_RemoveSlimeTrails(void) // killough 10/98
1089 byte
*hit
= calloc(1, numvertexes
); // Hitlist for vertices
1091 for (i
=0; i
<numsegs
; i
++) // Go through each seg
1095 if (segs
[i
].miniseg
== true) //figgi -- skip minisegs
1098 l
= segs
[i
].linedef
; // The parent linedef
1099 if (l
->dx
&& l
->dy
) // We can ignore orthogonal lines
1101 vertex_t
*v
= segs
[i
].v1
;
1103 if (!hit
[v
- vertexes
]) // If we haven't processed vertex
1105 hit
[v
- vertexes
] = 1; // Mark this vertex as processed
1106 if (v
!= l
->v1
&& v
!= l
->v2
) // Exclude endpoints of linedefs
1107 { // Project the vertex back onto the parent linedef
1108 int_64_t dx2
= (l
->dx
>> FRACBITS
) * (l
->dx
>> FRACBITS
);
1109 int_64_t dy2
= (l
->dy
>> FRACBITS
) * (l
->dy
>> FRACBITS
);
1110 int_64_t dxy
= (l
->dx
>> FRACBITS
) * (l
->dy
>> FRACBITS
);
1111 int_64_t s
= dx2
+ dy2
;
1112 int x0
= v
->x
, y0
= v
->y
, x1
= l
->v1
->x
, y1
= l
->v1
->y
;
1113 v
->x
= (int)((dx2
* x0
+ dy2
* x1
+ dxy
* (y0
- y1
)) / s
);
1114 v
->y
= (int)((dy2
* y0
+ dx2
* y1
+ dxy
* (x0
- x1
)) / s
);
1116 } // Obsfucated C contest entry: :)
1117 while ((v
!= segs
[i
].v2
) && (v
= segs
[i
].v2
));
1126 // killough 5/3/98: reformatted, cleaned up
1128 void P_SetupLevel(int episode
, int map
, int playermask
, skill_t skill
)
1137 totalkills
= totalitems
= totalsecret
= wminfo
.maxfrags
= 0;
1138 wminfo
.partime
= 180;
1140 for (i
=0; i
<MAXPLAYERS
; i
++)
1141 players
[i
].killcount
= players
[i
].secretcount
= players
[i
].itemcount
= 0;
1143 // Initial height of PointOfView will be set by player think.
1144 players
[consoleplayer
].viewz
= 1;
1146 // Make sure all sounds are stopped before Z_FreeTags.
1149 Z_FreeTags(PU_LEVEL
, PU_PURGELEVEL
-1);
1150 if (rejectlump
!= -1) { // cph - unlock the reject table
1151 W_UnlockLumpNum(rejectlump
);
1157 // if working with a devlopment map, reload it
1158 // W_Reload (); killough 1/31/98: W_Reload obsolete
1161 if (gamemode
== commercial
)
1164 snprintf (lumpname
,sizeof(lumpname
),"map0%d", map
);
1166 snprintf (lumpname
,sizeof(lumpname
),"map%d", map
);
1170 snprintf(lumpname
,sizeof(lumpname
), "E%dM%d", episode
, map
); // killough 1/24/98: simplify
1173 lumpnum
= W_GetNumForName(lumpname
);
1177 // note: most of this ordering is important
1179 // killough 3/1/98: P_LoadBlockMap call moved down to below
1180 // killough 4/4/98: split load of sidedefs into two parts,
1181 // to allow texture names to be used in special linedefs
1183 usingGLNodes
= false;
1184 P_LoadVertexes (lumpnum
+ML_VERTEXES
);
1185 P_LoadSectors (lumpnum
+ML_SECTORS
);
1186 P_LoadSideDefs (lumpnum
+ML_SIDEDEFS
);
1187 P_LoadLineDefs (lumpnum
+ML_LINEDEFS
);
1188 P_LoadSideDefs2 (lumpnum
+ML_SIDEDEFS
);
1189 P_LoadLineDefs2 (lumpnum
+ML_LINEDEFS
);
1190 P_LoadBlockMap (lumpnum
+ML_BLOCKMAP
);
1192 P_LoadSubsectors(lumpnum
+ ML_SSECTORS
);
1193 P_LoadNodes(lumpnum
+ ML_NODES
);
1194 P_LoadSegs(lumpnum
+ ML_SEGS
);
1196 if (rejectlump
!= -1)
1197 W_UnlockLumpNum(rejectlump
);
1198 rejectlump
= lumpnum
+ML_REJECT
;
1200 int rjlen
= W_LumpLength(rejectlump
);
1201 int rjreq
= (numsectors
*numsectors
+7)/8;
1202 if (rjlen
< rjreq
) {
1203 printf("P_SetupLevel: REJECT too short (%d<%d) - padded\n",rjlen
,rjreq
);
1204 rejectmatrix
= W_CacheLumpNumPadded(rejectlump
,rjreq
,0xff);
1206 rejectmatrix
= W_CacheLumpNum(rejectlump
);
1211 P_RemoveSlimeTrails(); // killough 10/98: remove slime trails from wad
1213 // Note: you don't need to clear player queue slots --
1214 // a much simpler fix is in g_game.c -- killough 10/98
1217 deathmatch_p
= deathmatchstarts
;
1219 P_LoadThings(lumpnum
+ML_THINGS
);
1221 // if deathmatch, randomly spawn the active players
1223 for (i
=0; i
<MAXPLAYERS
; i
++)
1224 if (playeringame
[i
])
1226 players
[i
].mo
= NULL
;
1227 G_DeathMatchSpawnPlayer(i
);
1230 // killough 3/26/98: Spawn icon landings:
1231 if (gamemode
==commercial
)
1232 P_SpawnBrainTargets();
1234 // clear special respawning que
1235 iquehead
= iquetail
= 0;
1237 // set up world state
1254 R_InitSprites(sprnames
);