1 // Emacs style mode select   -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // $Id: p_setup.cpp 4542 2014-02-09 17:39:42Z dr_sean $
5 //
6 // Copyright (C) 1993-1996 by id Software, Inc.
7 // Copyright (C) 2006-2014 by The Odamex Team.
8 //
9 // This program is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU General Public License
11 // as published by the Free Software Foundation; either version 2
12 // of the License, or (at your option) any later version.
13 //
14 // This program is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 // GNU General Public License for more details.
18 //
19 // DESCRIPTION:
20 //		Do all the WAD I/O, get map description,
21 //		set up initial state and misc. LUTs.
22 //
23 //-----------------------------------------------------------------------------
24 
25 
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <math.h>
29 #include <set>
30 
31 #include "m_alloc.h"
32 #include "m_vectors.h"
33 #include "m_argv.h"
34 #include "z_zone.h"
35 #include "m_swap.h"
36 #include "m_bbox.h"
37 #include "g_game.h"
38 #include "i_system.h"
39 #include "w_wad.h"
40 #include "doomdef.h"
41 #include "p_local.h"
42 #include "p_acs.h"
43 #include "s_sound.h"
44 #include "doomstat.h"
45 #include "p_lnspec.h"
46 #include "v_palette.h"
47 #include "c_console.h"
48 
49 #include "p_setup.h"
50 
51 void SV_PreservePlayer(player_t &player);
52 void P_SpawnMapThing (mapthing2_t *mthing, int position);
53 
54 void P_TranslateLineDef (line_t *ld, maplinedef_t *mld);
55 void P_TranslateTeleportThings (void);
56 int	P_TranslateSectorSpecial (int);
57 
58 static void P_SetupLevelFloorPlane(sector_t *sector);
59 static void P_SetupLevelCeilingPlane(sector_t *sector);
60 static void P_SetupSlopes();
61 void P_InvertPlane(plane_t *plane);
62 
63 extern unsigned int R_OldBlend;
64 
65 //
66 // MAP related Lookup tables.
67 // Store VERTEXES, LINEDEFS, SIDEDEFS, etc.
68 //
69 int 			numvertexes;
70 vertex_t*		vertexes;
71 
72 int 			numsegs;
73 seg_t*			segs;
74 
75 int 			numsectors;
76 sector_t*		sectors;
77 
78 int 			numsubsectors;
79 subsector_t*	subsectors;
80 
81 int 			numnodes;
82 node_t* 		nodes;
83 
84 int 			numlines;
85 line_t* 		lines;
86 
87 int 			numsides;
88 side_t* 		sides;
89 
90 // [RH] Set true if the map contains a BEHAVIOR lump
91 bool			HasBehavior = false;
92 
93 // BLOCKMAP
94 // Created from axis aligned bounding box
95 // of the map, a rectangular array of
96 // blocks of size ...
97 // Used to speed up collision detection
98 // by spatial subdivision in 2D.
99 //
100 // Blockmap size.
101 int 			bmapwidth;
102 int 			bmapheight; 	// size in mapblocks
103 
104 int				*blockmap;		// int for larger maps ([RH] Made int because BOOM does)
105 int				*blockmaplump;	// offsets in blockmap are from here
106 
107 fixed_t 		bmaporgx;		// origin of block map
108 fixed_t 		bmaporgy;
109 
110 AActor**		blocklinks;		// for thing chains
111 
112 
113 
114 // REJECT
115 // For fast sight rejection.
116 // Speeds up enemy AI by skipping detailed
117 //	LineOf Sight calculation.
118 // Without special effect, this could be
119 //	used as a PVS lookup as well.
120 //
121 byte*			rejectmatrix;
122 BOOL			rejectempty;
123 
124 
125 // Maintain single and multi player starting spots.
126 int				MaxDeathmatchStarts;
127 mapthing2_t		*deathmatchstarts;
128 mapthing2_t		*deathmatch_p;
129 
130 std::vector<mapthing2_t> playerstarts;
131 std::vector<mapthing2_t> voodoostarts;
132 
133 //	[Toke - CTF - starts] Teamplay starts
134 size_t			MaxBlueTeamStarts;
135 size_t			MaxRedTeamStarts;
136 
137 mapthing2_t		*blueteamstarts;
138 mapthing2_t		*redteamstarts;
139 
140 mapthing2_t		*blueteam_p;
141 mapthing2_t		*redteam_p;
142 
143 //
144 // P_LoadVertexes
145 //
P_LoadVertexes(int lump)146 void P_LoadVertexes (int lump)
147 {
148 	byte *data;
149 	int i;
150 
151 	// Determine number of vertices:
152 	//	total lump length / vertex record length.
153 	numvertexes = W_LumpLength (lump) / sizeof(mapvertex_t);
154 
155 	// Allocate zone memory for buffer.
156 	vertexes = (vertex_t *)Z_Malloc (numvertexes*sizeof(vertex_t), PU_LEVEL, 0);
157 
158 	// Load data into cache.
159 	data = (byte *)W_CacheLumpNum (lump, PU_STATIC);
160 
161 	// Copy and convert vertex coordinates,
162 	// internal representation as fixed.
163 	for (i = 0; i < numvertexes; i++)
164 	{
165 		vertexes[i].x = LESHORT(((mapvertex_t *)data)[i].x)<<FRACBITS;
166 		vertexes[i].y = LESHORT(((mapvertex_t *)data)[i].y)<<FRACBITS;
167 	}
168 
169 	// Free buffer memory.
170 	Z_Free (data);
171 }
172 
173 
174 
175 //
176 // P_LoadSegs
177 //
178 // killough 5/3/98: reformatted, cleaned up
179 
P_LoadSegs(int lump)180 void P_LoadSegs (int lump)
181 {
182 	int  i;
183 	byte *data;
184 
185 	numsegs = W_LumpLength (lump) / sizeof(mapseg_t);
186 	segs = (seg_t *)Z_Malloc (numsegs*sizeof(seg_t), PU_LEVEL, 0);
187 	memset (segs, 0, numsegs*sizeof(seg_t));
188 	data = (byte *)W_CacheLumpNum (lump, PU_STATIC);
189 
190 	for (i = 0; i < numsegs; i++)
191 	{
192 		seg_t *li = segs+i;
193 		mapseg_t *ml = (mapseg_t *) data + i;
194 
195 		int side, linedef;
196 		line_t *ldef;
197 
198 		unsigned short v = LESHORT(ml->v1);
199 
200 		if(v >= numvertexes)
201 			I_Error("P_LoadSegs: invalid vertex %d", v);
202 		else
203 			li->v1 = &vertexes[v];
204 
205 		v = LESHORT(ml->v2);
206 
207 		if(v >= numvertexes)
208 			I_Error("P_LoadSegs: invalid vertex %d", v);
209 		else
210 			li->v2 = &vertexes[v];
211 
212 		li->angle = (LESHORT(ml->angle))<<16;
213 
214 		li->offset = (LESHORT(ml->offset))<<16;
215 		linedef = LESHORT(ml->linedef);
216 
217 		if(linedef < 0 || linedef >= numlines)
218 			I_Error("P_LoadSegs: invalid linedef %d", linedef);
219 
220 		ldef = &lines[linedef];
221 		li->linedef = ldef;
222 
223 		side = LESHORT(ml->side);
224 
225 		if (side != 0 && side != 1)
226 			side = 1;	// assume invalid value means back
227 
228 		li->sidedef = &sides[ldef->sidenum[side]];
229 		li->frontsector = sides[ldef->sidenum[side]].sector;
230 
231 		// killough 5/3/98: ignore 2s flag if second sidedef missing:
232 		if (ldef->flags & ML_TWOSIDED && ldef->sidenum[side^1]!=R_NOSIDE)
233 			li->backsector = sides[ldef->sidenum[side^1]].sector;
234 		else
235 		{
236 			li->backsector = 0;
237 			ldef->flags &= ~ML_TWOSIDED;
238 		}
239 
240 		// recalculate seg offsets. values in wads are untrustworthy.
241 		vertex_t *from = (side == 0)
242 			? ldef->v1			// right side: offset is from start of linedef
243 			: ldef->v2;			// left side: offset is from end of linedef
244 		vertex_t *to = li->v1;	// end point is start of seg, in both cases
245 
246 		float dx = FIXED2FLOAT(to->x - from->x);
247 		float dy = FIXED2FLOAT(to->y - from->y);
248 		li->offset = FLOAT2FIXED(sqrt(dx * dx + dy * dy));
249 
250 		dx = FIXED2FLOAT(li->v2->x - li->v1->x);
251 		dy = FIXED2FLOAT(li->v2->y - li->v1->y);
252 		li->length = FLOAT2FIXED(sqrt(dx * dx + dy* dy));
253 	}
254 
255 	Z_Free (data);
256 }
257 
258 
259 //
260 // P_LoadSubsectors
261 //
P_LoadSubsectors(int lump)262 void P_LoadSubsectors (int lump)
263 {
264 	byte *data;
265 	int i;
266 
267 	numsubsectors = W_LumpLength (lump) / sizeof(mapsubsector_t);
268 	subsectors = (subsector_t *)Z_Malloc (numsubsectors*sizeof(subsector_t),PU_LEVEL,0);
269 	data = (byte *)W_CacheLumpNum (lump,PU_STATIC);
270 
271 	memset (subsectors, 0, numsubsectors*sizeof(subsector_t));
272 
273 	for (i = 0; i < numsubsectors; i++)
274 	{
275 		subsectors[i].numlines = (unsigned short)LESHORT(((mapsubsector_t *)data)[i].numsegs);
276 		subsectors[i].firstline = (unsigned short)LESHORT(((mapsubsector_t *)data)[i].firstseg);
277 	}
278 
279 	Z_Free (data);
280 }
281 
282 
283 
284 //
285 // P_LoadSectors
286 //
P_LoadSectors(int lump)287 void P_LoadSectors (int lump)
288 {
289 	byte*				data;
290 	int 				i;
291 	mapsector_t*		ms;
292 	sector_t*			ss;
293 	int					defSeqType;
294 
295 	// denis - properly destroy sectors so that smart pointers they contain don't get screwed
296 	delete[] sectors;
297 
298 	numsectors = W_LumpLength (lump) / sizeof(mapsector_t);
299 
300 	// denis - properly construct sectors so that smart pointers they contain don't get screwed
301 	sectors = new sector_t[numsectors];
302 	memset(sectors, 0, sizeof(sector_t)*numsectors);
303 
304 	data = (byte *)W_CacheLumpNum (lump, PU_STATIC);
305 
306 	if (level.flags & LEVEL_SNDSEQTOTALCTRL)
307 		defSeqType = 0;
308 	else
309 		defSeqType = -1;
310 
311 	ms = (mapsector_t *)data;
312 	ss = sectors;
313 	for (i = 0; i < numsectors; i++, ss++, ms++)
314 	{
315 		ss->floorheight = LESHORT(ms->floorheight)<<FRACBITS;
316 		ss->ceilingheight = LESHORT(ms->ceilingheight)<<FRACBITS;
317 		ss->floorpic = (short)R_FlatNumForName(ms->floorpic);
318 		ss->ceilingpic = (short)R_FlatNumForName(ms->ceilingpic);
319 		ss->lightlevel = LESHORT(ms->lightlevel);
320 		if (HasBehavior)
321 			ss->special = LESHORT(ms->special);
322 		else	// [RH] Translate to new sector special
323 			ss->special = P_TranslateSectorSpecial (LESHORT(ms->special));
324 		ss->tag = LESHORT(ms->tag);
325 		ss->thinglist = NULL;
326 		ss->touching_thinglist = NULL;		// phares 3/14/98
327 		ss->seqType = defSeqType;
328 		ss->nextsec = -1;	//jff 2/26/98 add fields to support locking out
329 		ss->prevsec = -1;	// stair retriggering until build completes
330 
331 		// killough 3/7/98:
332 		ss->floor_xoffs = 0;
333 		ss->floor_yoffs = 0;	// floor and ceiling flats offsets
334 		ss->ceiling_xoffs = 0;
335 		ss->ceiling_yoffs = 0;
336 
337 		ss->floor_xscale = FRACUNIT;	// [RH] floor and ceiling scaling
338 		ss->floor_yscale = FRACUNIT;
339 		ss->ceiling_xscale = FRACUNIT;
340 		ss->ceiling_yscale = FRACUNIT;
341 
342 		ss->floor_angle = 0;	// [RH] floor and ceiling rotation
343 		ss->ceiling_angle = 0;
344 
345 		ss->base_ceiling_angle = ss->base_ceiling_yoffs =
346 			ss->base_floor_angle = ss->base_floor_yoffs = 0;
347 
348 		ss->heightsec = NULL;	// sector used to get floor and ceiling height
349 		ss->floorlightsec = NULL;	// sector used to get floor lighting
350 		// killough 3/7/98: end changes
351 
352 		// killough 4/11/98 sector used to get ceiling lighting:
353 		ss->ceilinglightsec = NULL;
354 
355 		// [SL] 2012-01-17 - init the sector's floor and ceiling planes
356 		// as level planes (constant value of z for all points)
357 		// Slopes will be setup later
358 		P_SetupLevelFloorPlane(ss);
359 		P_SetupLevelCeilingPlane(ss);
360 
361 		ss->gravity = 1.0f;	// [RH] Default sector gravity of 1.0
362 
363 		// [RH] Sectors default to white light with the default fade.
364 		//		If they are outside (have a sky ceiling), they use the outside fog.
365 		if (level.outsidefog != 0xff000000 && ss->ceilingpic == skyflatnum)
366 			ss->ceilingcolormap = ss->floorcolormap = GetSpecialLights (255,255,255,
367 				RPART(level.outsidefog),GPART(level.outsidefog),BPART(level.outsidefog));
368 		else
369 			ss->ceilingcolormap = ss->floorcolormap = GetSpecialLights (255,255,255,
370 				RPART(level.fadeto),GPART(level.fadeto),BPART(level.fadeto));
371 
372 		ss->sky = 0;
373 
374 		// killough 8/28/98: initialize all sectors to normal friction
375 		ss->friction = ORIG_FRICTION;
376 		ss->movefactor = ORIG_FRICTION_FACTOR;
377 	}
378 
379 	Z_Free (data);
380 }
381 
382 
383 //
384 // P_LoadNodes
385 //
P_LoadNodes(int lump)386 void P_LoadNodes (int lump)
387 {
388 	byte*		data;
389 	int 		i;
390 	int 		j;
391 	int 		k;
392 	mapnode_t*	mn;
393 	node_t* 	no;
394 
395 	numnodes = W_LumpLength (lump) / sizeof(mapnode_t);
396 	nodes = (node_t *)Z_Malloc (numnodes*sizeof(node_t), PU_LEVEL, 0);
397 	data = (byte *)W_CacheLumpNum (lump, PU_STATIC);
398 
399 	mn = (mapnode_t *)data;
400 	no = nodes;
401 
402 	for (i = 0; i < numnodes; i++, no++, mn++)
403 	{
404 		no->x = LESHORT(mn->x)<<FRACBITS;
405 		no->y = LESHORT(mn->y)<<FRACBITS;
406 		no->dx = LESHORT(mn->dx)<<FRACBITS;
407 		no->dy = LESHORT(mn->dy)<<FRACBITS;
408 		for (j = 0; j < 2; j++)
409 		{
410 			// account for children's promotion to 32 bits
411 			unsigned int child = (unsigned short)LESHORT(mn->children[j]);
412 
413 			if (child == 0xffff)
414 				child = 0xffffffff;
415 			else if (child & 0x8000)
416 				child = (child & ~0x8000) | NF_SUBSECTOR;
417 
418 			no->children[j] = child;
419 
420 			for (k = 0; k < 4; k++)
421 				no->bbox[j][k] = LESHORT(mn->bbox[j][k]) << FRACBITS;
422 		}
423 	}
424 
425 	Z_Free (data);
426 }
427 
428 //
429 // P_LoadXNOD - load ZDBSP extended nodes
430 // returns false if nodes are not extended to fall back to original nodes
431 //
P_LoadXNOD(int lump)432 bool P_LoadXNOD(int lump)
433 {
434 	size_t len = W_LumpLength(lump);
435 	byte *data = (byte *) W_CacheLumpNum(lump, PU_STATIC);
436 
437 	if (len < 4 || memcmp(data, "XNOD", 4) != 0)
438 	{
439 		Z_Free(data);
440 		return false;
441 	}
442 
443 	byte *p = data + 4; // skip the magic number
444 
445 	// Load vertices
446 	unsigned int numorgvert = LELONG(*(unsigned int *)p); p += 4;
447 	unsigned int numnewvert = LELONG(*(unsigned int *)p); p += 4;
448 
449 	vertex_t *newvert = (vertex_t *) Z_Malloc((numorgvert + numnewvert)*sizeof(*newvert), PU_LEVEL, 0);
450 
451 	memcpy(newvert, vertexes, numorgvert*sizeof(*newvert));
452 	memset(&newvert[numorgvert], 0, numnewvert * sizeof(*newvert));
453 
454 	for (unsigned int i = 0; i < numnewvert; i++)
455 	{
456 		vertex_t *v = &newvert[numorgvert+i];
457 		v->x = LELONG(*(int *)p); p += 4;
458 		v->y = LELONG(*(int *)p); p += 4;
459 	}
460 
461 	// Adjust linedefs - since we reallocated the vertex array,
462 	// all vertex pointers in linedefs must be updated
463 
464 	for (int i = 0; i < numlines; i++)
465 	{
466 		lines[i].v1 = newvert + (lines[i].v1 - vertexes);
467 		lines[i].v2 = newvert + (lines[i].v2 - vertexes);
468 	}
469 
470 	// nuke the old list, update globals to point to the new list
471 	Z_Free(vertexes);
472 	vertexes = newvert;
473 	numvertexes = numorgvert + numnewvert;
474 
475 	// Load subsectors
476 
477 	numsubsectors = LELONG(*(unsigned int *)p); p += 4;
478 	subsectors = (subsector_t *) Z_Malloc(numsubsectors * sizeof(*subsectors), PU_LEVEL, 0);
479 	memset(subsectors, 0, numsubsectors * sizeof(*subsectors));
480 
481 	unsigned int first_seg = 0;
482 
483 	for (int i = 0; i < numsubsectors; i++)
484 	{
485 		subsectors[i].firstline = first_seg;
486 		subsectors[i].numlines = LELONG(*(unsigned int *)p); p += 4;
487 		first_seg += subsectors[i].numlines;
488 	}
489 
490 	// Load segs
491 
492 	numsegs = LELONG(*(unsigned int *)p); p += 4;
493 	segs = (seg_t *) Z_Malloc(numsegs * sizeof(*segs), PU_LEVEL, 0);
494 	memset(segs, 0, numsegs * sizeof(*segs));
495 
496 	for (int i = 0; i < numsegs; i++)
497 	{
498 		unsigned int v1 = LELONG(*(unsigned int *)p); p += 4;
499 		unsigned int v2 = LELONG(*(unsigned int *)p); p += 4;
500 		unsigned short ld = LESHORT(*(unsigned short *)p); p += 2;
501 		unsigned char side = *(unsigned char *)p; p += 1;
502 
503 		if (side != 0 && side != 1)
504 			side = 1;
505 
506 		seg_t *seg = &segs[i];
507 		line_t *line = &lines[ld];
508 
509 		seg->v1 = &vertexes[v1];
510 		seg->v2 = &vertexes[v2];
511 
512 		seg->linedef = line;
513 		seg->sidedef = &sides[line->sidenum[side]];
514 
515 		seg->frontsector = seg->sidedef->sector;
516 		if (line->flags & ML_TWOSIDED && line->sidenum[side^1] != R_NOSIDE)
517 			seg->backsector = sides[line->sidenum[side^1]].sector;
518 		else
519 			seg->backsector = NULL;
520 
521 		seg->angle = R_PointToAngle2(seg->v1->x, seg->v1->y, seg->v2->x, seg->v2->y);
522 
523 		// a short version of the offset calculation in P_LoadSegs
524 		vertex_t *origin = (side == 0) ? line->v1 : line->v2;
525 		float dx = FIXED2FLOAT(seg->v1->x - origin->x);
526 		float dy = FIXED2FLOAT(seg->v1->y - origin->y);
527 		seg->offset = FLOAT2FIXED(sqrt(dx * dx + dy * dy));
528 	}
529 
530 	// Load nodes
531 
532 	numnodes = LELONG(*(unsigned int *)p); p += 4;
533 	nodes = (node_t *) Z_Malloc(numnodes * sizeof(*nodes), PU_LEVEL, 0);
534 	memset(nodes, 0, numnodes * sizeof(*nodes));
535 
536 	for (int i = 0; i < numnodes; i++)
537 	{
538 		node_t *node = &nodes[i];
539 
540 		node->x = LESHORT(*(short *)p)<<FRACBITS; p += 2;
541 		node->y = LESHORT(*(short *)p)<<FRACBITS; p += 2;
542 		node->dx = LESHORT(*(short *)p)<<FRACBITS; p += 2;
543 		node->dy = LESHORT(*(short *)p)<<FRACBITS; p += 2;
544 
545 		for (int j = 0; j < 2; j++)
546 		{
547 			for (int k = 0; k < 4; k++)
548 			{
549 				node->bbox[j][k] = LESHORT(*(short *)p)<<FRACBITS; p += 2;
550 			}
551 		}
552 
553 		for (int j = 0; j < 2; j++)
554 		{
555 			node->children[j] = LELONG(*(unsigned int *)p); p += 4;
556 		}
557 	}
558 
559 	Z_Free(data);
560 
561 	return true;
562 }
563 
564 //
565 // P_LoadThings
566 //
P_LoadThings(int lump)567 void P_LoadThings (int lump)
568 {
569 	mapthing2_t mt2;		// [RH] for translation
570 	byte *data = (byte *)W_CacheLumpNum (lump, PU_STATIC);
571 	mapthing_t *mt = (mapthing_t *)data;
572 	mapthing_t *lastmt = (mapthing_t *)(data + W_LumpLength (lump));
573 
574 	playerstarts.clear();
575 	voodoostarts.clear();
576 
577 	// [RH] ZDoom now uses Hexen-style maps as its native format. // denis - growwwwl
578 	//		Since this is the only place where Doom-style Things are ever
579 	//		referenced, we translate them into a Hexen-style thing.
580 	memset (&mt2, 0, sizeof(mt2));
581 
582 	for ( ; mt < lastmt; mt++)
583 	{
584 		// [RH] At this point, monsters unique to Doom II were weeded out
585 		//		if the IWAD wasn't for Doom II. R_SpawnMapThing() can now
586 		//		handle these and more cases better, so we just pass it
587 		//		everything and let it decide what to do with them.
588 
589 		// [RH] Need to translate the spawn flags to Hexen format.
590 		short flags = LESHORT(mt->options);
591 		mt2.flags = (short)((flags & 0xf) | 0x7e0);
592 		if (flags & BTF_NOTSINGLE)			mt2.flags &= ~MTF_SINGLE;
593 		if (flags & BTF_NOTDEATHMATCH)		mt2.flags &= ~MTF_DEATHMATCH;
594 		if (flags & BTF_NOTCOOPERATIVE)		mt2.flags &= ~MTF_COOPERATIVE;
595 
596 		mt2.x = LESHORT(mt->x);
597 		mt2.y = LESHORT(mt->y);
598 		mt2.angle = LESHORT(mt->angle);
599 		mt2.type = LESHORT(mt->type);
600 
601 		P_SpawnMapThing (&mt2, 0);
602 	}
603 
604 	Z_Free (data);
605 }
606 
607 // [RH]
608 // P_LoadThings2
609 //
610 // Same as P_LoadThings() except it assumes Things are
611 // saved Hexen-style. Position also controls which single-
612 // player start spots are spawned by filtering out those
613 // whose first parameter don't match position.
614 //
P_LoadThings2(int lump,int position)615 void P_LoadThings2 (int lump, int position)
616 {
617 	byte *data = (byte *)W_CacheLumpNum (lump, PU_STATIC);
618 	mapthing2_t *mt = (mapthing2_t *)data;
619 	mapthing2_t *lastmt = (mapthing2_t *)(data + W_LumpLength (lump));
620 
621 	playerstarts.clear();
622 	voodoostarts.clear();
623 
624 	for ( ; mt < lastmt; mt++)
625 	{
626 		// [RH] At this point, monsters unique to Doom II were weeded out
627 		//		if the IWAD wasn't for Doom II. R_SpawnMapThing() can now
628 		//		handle these and more cases better, so we just pass it
629 		//		everything and let it decide what to do with them.
630 
631 		mt->thingid = LESHORT(mt->thingid);
632 		mt->x = LESHORT(mt->x);
633 		mt->y = LESHORT(mt->y);
634 		mt->z = LESHORT(mt->z);
635 		mt->angle = LESHORT(mt->angle);
636 		mt->type = LESHORT(mt->type);
637 		mt->flags = LESHORT(mt->flags);
638 
639 		P_SpawnMapThing (mt, position);
640 	}
641 
642 	Z_Free (data);
643 }
644 
645 //
646 // P_LoadLineDefs
647 //
648 // killough 4/4/98: split into two functions, to allow sidedef overloading
649 //
650 // [RH] Actually split into four functions to allow for Hexen and Doom
651 //		linedefs.
P_AdjustLine(line_t * ld)652 void P_AdjustLine (line_t *ld)
653 {
654 	vertex_t *v1, *v2;
655 
656 	ld->lucency = 255;	// [RH] Opaque by default
657 
658 	v1 = ld->v1;
659 	v2 = ld->v2;
660 
661 	ld->dx = v2->x - v1->x;
662 	ld->dy = v2->y - v1->y;
663 
664 	if (ld->dx == 0)
665 		ld->slopetype = ST_VERTICAL;
666 	else if (ld->dy == 0)
667 		ld->slopetype = ST_HORIZONTAL;
668 	else
669 		ld->slopetype = (FixedDiv (ld->dy , ld->dx) > 0) ? ST_POSITIVE : ST_NEGATIVE;
670 
671 	if (v1->x < v2->x)
672 	{
673 		ld->bbox[BOXLEFT] = v1->x;
674 		ld->bbox[BOXRIGHT] = v2->x;
675 	}
676 	else
677 	{
678 		ld->bbox[BOXLEFT] = v2->x;
679 		ld->bbox[BOXRIGHT] = v1->x;
680 	}
681 
682 	if (v1->y < v2->y)
683 	{
684 		ld->bbox[BOXBOTTOM] = v1->y;
685 		ld->bbox[BOXTOP] = v2->y;
686 	}
687 	else
688 	{
689 		ld->bbox[BOXBOTTOM] = v2->y;
690 		ld->bbox[BOXTOP] = v1->y;
691 	}
692 
693 	// [RH] Set line id (as appropriate) here
694 	if (ld->special == Line_SetIdentification ||
695 		ld->special == Teleport_Line ||
696 		ld->special == TranslucentLine ||
697 		ld->special == Scroll_Texture_Model) {
698 		ld->id = ld->args[0];
699 	}
700 
701 	// denis - prevent buffer overrun
702 	if(*ld->sidenum == R_NOSIDE)
703 		return;
704 
705 	// killough 4/4/98: support special sidedef interpretation below
706 	if (// [RH] Save Static_Init only if it's interested in the textures
707 		( (ld->special == Static_Init && ld->args[1] == Init_Color)
708 			|| ld->special != Static_Init) ) {
709 			sides[*ld->sidenum].special = ld->special;
710 			sides[*ld->sidenum].tag = ld->args[0];
711 		}
712 	else
713 		sides[*ld->sidenum].special = 0;
714 }
715 
716 // killough 4/4/98: delay using sidedefs until they are loaded
P_FinishLoadingLineDefs(void)717 void P_FinishLoadingLineDefs (void)
718 {
719 	int i, linenum;
720 	register line_t *ld = lines;
721 
722 	for (i = numlines, linenum = 0; i--; ld++, linenum++)
723 	{
724 		ld->frontsector = ld->sidenum[0]!=R_NOSIDE ? sides[ld->sidenum[0]].sector : 0;
725 		ld->backsector  = ld->sidenum[1]!=R_NOSIDE ? sides[ld->sidenum[1]].sector : 0;
726 		if (ld->sidenum[0] != R_NOSIDE)
727 			sides[ld->sidenum[0]].linenum = linenum;
728 		if (ld->sidenum[1] != R_NOSIDE)
729 			sides[ld->sidenum[1]].linenum = linenum;
730 
731 		switch (ld->special)
732 		{						// killough 4/11/98: handle special types
733 			int j;
734 
735 			case TranslucentLine:			// killough 4/11/98: translucent 2s textures
736 #if 0
737 				lump = sides[*ld->sidenum].special;		// translucency from sidedef
738 				if (!ld->tag)							// if tag==0,
739 					ld->tranlump = lump;				// affect this linedef only
740 				else
741 					for (j=0;j<numlines;j++)			// if tag!=0,
742 						if (lines[j].tag == ld->tag)	// affect all matching linedefs
743 							lines[j].tranlump = lump;
744 #else
745 				// [RH] Second arg controls how opaque it is.
746 				if (!ld->args[0])
747 					ld->lucency = (byte)ld->args[1];
748 				else
749 					for (j = 0; j < numlines; j++)
750 						if (lines[j].id == ld->args[0])
751 							lines[j].lucency = (byte)ld->args[1];
752 #endif
753 				break;
754 		}
755 	}
756 }
757 
P_LoadLineDefs(int lump)758 void P_LoadLineDefs (int lump)
759 {
760 	byte *data;
761 	int i;
762 	line_t *ld;
763 
764 	numlines = W_LumpLength (lump) / sizeof(maplinedef_t);
765 	lines = (line_t *)Z_Malloc (numlines*sizeof(line_t), PU_LEVEL, 0);
766 	memset (lines, 0, numlines*sizeof(line_t));
767 	data = (byte *)W_CacheLumpNum (lump, PU_STATIC);
768 
769 	ld = lines;
770 	for (i=0 ; i<numlines ; i++, ld++)
771 	{
772 		maplinedef_t *mld = ((maplinedef_t *)data) + i;
773 
774 		// [RH] Translate old linedef special and flags to be
775 		//		compatible with the new format.
776 		P_TranslateLineDef (ld, mld);
777 
778 		unsigned short v = LESHORT(mld->v1);
779 
780 		if(v >= numvertexes)
781 			I_Error("P_LoadLineDefs: invalid vertex %d", v);
782 		else
783 			ld->v1 = &vertexes[v];
784 
785 		v = LESHORT(mld->v2);
786 
787 		if(v >= numvertexes)
788 			I_Error("P_LoadLineDefs: invalid vertex %d", v);
789 		else
790 			ld->v2 = &vertexes[v];
791 
792 		ld->sidenum[0] = LESHORT(mld->sidenum[0]);
793 		ld->sidenum[1] = LESHORT(mld->sidenum[1]);
794 
795 		if(ld->sidenum[0] >= numsides)
796 			ld->sidenum[0] = R_NOSIDE;
797 		if(ld->sidenum[1] >= numsides)
798 			ld->sidenum[1] = R_NOSIDE;
799 
800 		P_AdjustLine (ld);
801 	}
802 
803 	Z_Free (data);
804 }
805 
806 // [RH] Same as P_LoadLineDefs() except it uses Hexen-style LineDefs.
P_LoadLineDefs2(int lump)807 void P_LoadLineDefs2 (int lump)
808 {
809 	byte*				data;
810 	int 				i;
811 	maplinedef2_t*		mld;
812 	line_t* 			ld;
813 
814 	numlines = W_LumpLength (lump) / sizeof(maplinedef2_t);
815 	lines = (line_t *)Z_Malloc (numlines*sizeof(line_t), PU_LEVEL,0 );
816 	memset (lines, 0, numlines*sizeof(line_t));
817 	data = (byte *)W_CacheLumpNum (lump, PU_STATIC);
818 
819 	mld = (maplinedef2_t *)data;
820 	ld = lines;
821 	for (i = 0; i < numlines; i++, mld++, ld++)
822 	{
823 		int j;
824 
825 		for (j = 0; j < 5; j++)
826 			ld->args[j] = mld->args[j];
827 
828 		ld->flags = LESHORT(mld->flags);
829 		ld->special = mld->special;
830 
831 		unsigned short v = LESHORT(mld->v1);
832 
833 		if(v >= numvertexes)
834 			I_Error("P_LoadLineDefs: invalid vertex %d", v);
835 		else
836 			ld->v1 = &vertexes[v];
837 
838 		v = LESHORT(mld->v2);
839 
840 		if(v >= numvertexes)
841 			I_Error("P_LoadLineDefs: invalid vertex %d", v);
842 		else
843 			ld->v2 = &vertexes[v];
844 
845 		ld->sidenum[0] = LESHORT(mld->sidenum[0]);
846 		ld->sidenum[1] = LESHORT(mld->sidenum[1]);
847 
848 		if(ld->sidenum[0] >= numsides)
849 			ld->sidenum[0] = R_NOSIDE;
850 		if(ld->sidenum[1] >= numsides)
851 			ld->sidenum[1] = R_NOSIDE;
852 
853 		P_AdjustLine (ld);
854 	}
855 
856 	Z_Free (data);
857 }
858 
859 //
860 // P_LoadSideDefs
861 //
862 // killough 4/4/98: split into two functions
P_LoadSideDefs(int lump)863 void P_LoadSideDefs (int lump)
864 {
865 	numsides = W_LumpLength (lump) / sizeof(mapsidedef_t);
866 	sides = (side_t *)Z_Malloc (numsides*sizeof(side_t), PU_LEVEL, 0);
867 	memset (sides, 0, numsides*sizeof(side_t));
868 }
869 
870 // [RH] Figure out blends for deep water sectors
SetTexture(short * texture,unsigned int * blend,char * name)871 static void SetTexture (short *texture, unsigned int *blend, char *name)
872 {
873 	if ((*blend = R_ColormapNumForName (name)) == 0) {
874 		if ((*texture = R_CheckTextureNumForName (name)) == -1) {
875 			char name2[9];
876 			char *stop;
877 			strncpy (name2, name, 8);
878 			name2[8] = 0;
879 			*blend = strtoul (name2, &stop, 16);
880 			*texture = 0;
881 		} else {
882 			*blend = 0;
883 		}
884 	} else {
885 		*texture = 0;
886 	}
887 }
888 
SetTextureNoErr(short * texture,unsigned int * color,char * name)889 static void SetTextureNoErr (short *texture, unsigned int *color, char *name)
890 {
891 	if ((*texture = R_CheckTextureNumForName (name)) == -1) {
892 		char name2[9];
893 		char *stop;
894 		strncpy (name2, name, 8);
895 		name2[8] = 0;
896 		*color = strtoul (name2, &stop, 16);
897 		*texture = 0;
898 	}
899 }
900 
901 // killough 4/4/98: delay using texture names until
902 // after linedefs are loaded, to allow overloading.
903 // killough 5/3/98: reformatted, cleaned up
904 
P_LoadSideDefs2(int lump)905 void P_LoadSideDefs2 (int lump)
906 {
907 	byte *data = (byte *)W_CacheLumpNum(lump,PU_STATIC);
908 	int  i;
909 
910 	for (i=0; i<numsides; i++)
911 	{
912 		register mapsidedef_t *msd = (mapsidedef_t *) data + i;
913 		register side_t *sd = sides + i;
914 		register sector_t *sec;
915 
916 		sd->textureoffset = LESHORT(msd->textureoffset)<<FRACBITS;
917 		sd->rowoffset = LESHORT(msd->rowoffset)<<FRACBITS;
918 		sd->linenum = -1;
919 
920 		// killough 4/4/98: allow sidedef texture names to be overloaded
921 		// killough 4/11/98: refined to allow colormaps to work as wall
922 		// textures if invalid as colormaps but valid as textures.
923 
924 		sd->sector = sec = &sectors[LESHORT(msd->sector)];
925 		switch (sd->special)
926 		{
927 		  case Transfer_Heights:	// variable colormap via 242 linedef
928 			  // [RH] The colormap num we get here isn't really a colormap,
929 			  //	  but a packed ARGB word for blending, so we also allow
930 			  //	  the blend to be specified directly by the texture names
931 			  //	  instead of figuring something out from the colormap.
932 			SetTexture (&sd->bottomtexture, &sec->bottommap, msd->bottomtexture);
933 			SetTexture (&sd->midtexture, &sec->midmap, msd->midtexture);
934 			SetTexture (&sd->toptexture, &sec->topmap, msd->toptexture);
935 			break;
936 
937 		  case Static_Init:
938 			// [RH] Set sector color and fog
939 			// upper "texture" is light color
940 			// lower "texture" is fog color
941 			{
942 				unsigned int color = 0xffffff, fog = 0x000000;
943 
944 				SetTextureNoErr (&sd->bottomtexture, &fog, msd->bottomtexture);
945 				SetTextureNoErr (&sd->toptexture, &color, msd->toptexture);
946 				sd->midtexture = R_TextureNumForName (msd->midtexture);
947 
948 				if (fog != 0x000000 || color != 0xffffff) {
949 					int s;
950 					dyncolormap_t *colormap = GetSpecialLights
951 						(RPART(color),	GPART(color),	BPART(color),
952 						 RPART(fog),	GPART(fog),		BPART(fog));
953 
954 					for (s = 0; s < numsectors; s++) {
955 						if (sectors[s].tag == sd->tag)
956 							sectors[s].ceilingcolormap =
957 								sectors[s].floorcolormap = colormap;
958 					}
959 				}
960 			}
961 			break;
962 
963 /*
964 		  case TranslucentLine:	// killough 4/11/98: apply translucency to 2s normal texture
965 			sd->midtexture = strncasecmp("TRANMAP", msd->midtexture, 8) ?
966 				(sd->special = W_CheckNumForName(msd->midtexture)) < 0 ||
967 				W_LumpLength(sd->special) != 65536 ?
968 				sd->special=0, R_TextureNumForName(msd->midtexture) :
969 					(sd->special++, 0) : (sd->special=0);
970 			sd->toptexture = R_TextureNumForName(msd->toptexture);
971 			sd->bottomtexture = R_TextureNumForName(msd->bottomtexture);
972 			break;
973 */
974 		  default:			// normal cases
975 			sd->midtexture = R_TextureNumForName(msd->midtexture);
976 			sd->toptexture = R_TextureNumForName(msd->toptexture);
977 			sd->bottomtexture = R_TextureNumForName(msd->bottomtexture);
978 			break;
979 		}
980 	}
981 	Z_Free (data);
982 }
983 
984 
985 //
986 // jff 10/6/98
987 // New code added to speed up calculation of internal blockmap
988 // Algorithm is order of nlines*(ncols+nrows) not nlines*ncols*nrows
989 //
990 
991 #define blkshift 7               /* places to shift rel position for cell num */
992 #define blkmask ((1<<blkshift)-1)/* mask for rel position within cell */
993 #define blkmargin 0              /* size guardband around map used */
994                                  // jff 10/8/98 use guardband>0
995                                  // jff 10/12/98 0 ok with + 1 in rows,cols
996 
997 typedef struct linelist_t        // type used to list lines in each block
998 {
999 	int		num;
1000 	struct	linelist_t *next;
1001 } linelist_t;
1002 
1003 //
1004 // Subroutine to add a line number to a block list
1005 // It simply returns if the line is already in the block
1006 //
1007 
AddBlockLine(linelist_t ** lists,int * count,int * done,int blockno,DWORD lineno)1008 static void AddBlockLine
1009 (
1010 	linelist_t **lists,
1011 	int *count,
1012 	int *done,
1013 	int blockno,
1014 	DWORD lineno
1015 )
1016 {
1017 	linelist_t *l;
1018 
1019 	if (done[blockno])
1020 		return;
1021 
1022 	l = new linelist_t;
1023 	l->num = lineno;
1024 	l->next = lists[blockno];
1025 	lists[blockno] = l;
1026 	count[blockno]++;
1027 	done[blockno] = 1;
1028 }
1029 
1030 //
1031 // Actually construct the blockmap lump from the level data
1032 //
1033 // This finds the intersection of each linedef with the column and
1034 // row lines at the left and bottom of each blockmap cell. It then
1035 // adds the line to all block lists touching the intersection.
1036 //
1037 
P_CreateBlockMap()1038 void P_CreateBlockMap()
1039 {
1040 	int xorg,yorg;					// blockmap origin (lower left)
1041 	int nrows,ncols;				// blockmap dimensions
1042 	linelist_t **blocklists=NULL;	// array of pointers to lists of lines
1043 	int *blockcount=NULL;			// array of counters of line lists
1044 	int *blockdone=NULL;			// array keeping track of blocks/line
1045 	int NBlocks;					// number of cells = nrows*ncols
1046 	DWORD linetotal=0;				// total length of all blocklists
1047 	int i,j;
1048 	int map_minx=MAXINT;			// init for map limits search
1049 	int map_miny=MAXINT;
1050 	int map_maxx=MININT;
1051 	int map_maxy=MININT;
1052 
1053 	// scan for map limits, which the blockmap must enclose
1054 
1055 	for (i = 0; i < numvertexes; i++)
1056 	{
1057 		fixed_t t;
1058 
1059 		if ((t=vertexes[i].x) < map_minx)
1060 			map_minx = t;
1061 		else if (t > map_maxx)
1062 			map_maxx = t;
1063 		if ((t=vertexes[i].y) < map_miny)
1064 			map_miny = t;
1065 		else if (t > map_maxy)
1066 			map_maxy = t;
1067 	}
1068 	map_minx >>= FRACBITS;    // work in map coords, not fixed_t
1069 	map_maxx >>= FRACBITS;
1070 	map_miny >>= FRACBITS;
1071 	map_maxy >>= FRACBITS;
1072 
1073 	// set up blockmap area to enclose level plus margin
1074 
1075 	xorg = map_minx-blkmargin;
1076 	yorg = map_miny-blkmargin;
1077 	ncols = (map_maxx+blkmargin-xorg+1+blkmask)>>blkshift;	//jff 10/12/98
1078 	nrows = (map_maxy+blkmargin-yorg+1+blkmask)>>blkshift;	//+1 needed for
1079 	NBlocks = ncols*nrows;									//map exactly 1 cell
1080 
1081 	// create the array of pointers on NBlocks to blocklists
1082 	// also create an array of linelist counts on NBlocks
1083 	// finally make an array in which we can mark blocks done per line
1084 
1085 	blocklists = new linelist_t *[NBlocks];
1086 	memset (blocklists, 0, NBlocks*sizeof(linelist_t *));
1087 	blockcount = new int[NBlocks];
1088 	memset (blockcount, 0, NBlocks*sizeof(int));
1089 	blockdone = new int[NBlocks];
1090 
1091 	// initialize each blocklist, and enter the trailing -1 in all blocklists
1092 	// note the linked list of lines grows backwards
1093 
1094 	for (i = 0; i < NBlocks; i++)
1095 	{
1096 		blocklists[i] = new linelist_t;
1097 		blocklists[i]->num = -1;
1098 		blocklists[i]->next = NULL;
1099 		blockcount[i]++;
1100 	}
1101 
1102 	// For each linedef in the wad, determine all blockmap blocks it touches,
1103 	// and add the linedef number to the blocklists for those blocks
1104 
1105 	for (i = 0; i < numlines; i++)
1106 	{
1107 		int x1 = lines[i].v1->x>>FRACBITS;		// lines[i] map coords
1108 		int y1 = lines[i].v1->y>>FRACBITS;
1109 		int x2 = lines[i].v2->x>>FRACBITS;
1110 		int y2 = lines[i].v2->y>>FRACBITS;
1111 		int dx = x2-x1;
1112 		int dy = y2-y1;
1113 		int vert = !dx;							// lines[i] slopetype
1114 		int horiz = !dy;
1115 		int spos = (dx^dy) > 0;
1116 		int sneg = (dx^dy) < 0;
1117 		int bx,by;								// block cell coords
1118 		int minx = x1>x2? x2 : x1;				// extremal lines[i] coords
1119 		int maxx = x1>x2? x1 : x2;
1120 		int miny = y1>y2? y2 : y1;
1121 		int maxy = y1>y2? y1 : y2;
1122 
1123 		// no blocks done for this linedef yet
1124 
1125 		memset (blockdone, 0, NBlocks*sizeof(int));
1126 
1127 		// The line always belongs to the blocks containing its endpoints
1128 
1129 		bx = (x1-xorg) >> blkshift;
1130 		by = (y1-yorg) >> blkshift;
1131 		AddBlockLine (blocklists, blockcount, blockdone, by*ncols+bx, i);
1132 		bx = (x2-xorg) >> blkshift;
1133 		by = (y2-yorg) >> blkshift;
1134 		AddBlockLine (blocklists, blockcount, blockdone, by*ncols+bx, i);
1135 
1136 		// For each column, see where the line along its left edge, which
1137 		// it contains, intersects the Linedef i. Add i to each corresponding
1138 		// blocklist.
1139 
1140 		if (!vert)    // don't interesect vertical lines with columns
1141 		{
1142 			for (j=0;j<ncols;j++)
1143 			{
1144 				// intersection of Linedef with x=xorg+(j<<blkshift)
1145 				// (y-y1)*dx = dy*(x-x1)
1146 				// y = dy*(x-x1)+y1*dx;
1147 
1148 				int x = xorg+(j<<blkshift);		// (x,y) is intersection
1149 				int y = (dy*(x-x1))/dx+y1;
1150 				int yb = (y-yorg)>>blkshift;	// block row number
1151 				int yp = (y-yorg)&blkmask;		// y position within block
1152 
1153 				if (yb<0 || yb>nrows-1)			// outside blockmap, continue
1154 					continue;
1155 
1156 				if (x<minx || x>maxx)			// line doesn't touch column
1157 					continue;
1158 
1159 				// The cell that contains the intersection point is always added
1160 
1161 				AddBlockLine(blocklists,blockcount,blockdone,ncols*yb+j,i);
1162 
1163 				// if the intersection is at a corner it depends on the slope
1164 				// (and whether the line extends past the intersection) which
1165 				// blocks are hit
1166 
1167 				if (yp==0)			// intersection at a corner
1168 				{
1169 					if (sneg)		//   \ - blocks x,y-, x-,y
1170 					{
1171 						if (yb>0 && miny<y)
1172 							AddBlockLine(blocklists, blockcount, blockdone, ncols*(yb-1)+j, i);
1173 						if (j>0 && minx<x)
1174 							AddBlockLine(blocklists, blockcount, blockdone, ncols*yb+j-1, i);
1175 					}
1176 					else if (spos)	//   / - block x-,y-
1177 					{
1178 						if (yb>0 && j>0 && minx<x)
1179 							AddBlockLine(blocklists,blockcount,blockdone,ncols*(yb-1)+j-1,i);
1180 					}
1181 					else if (horiz)	//   - - block x-,y
1182 					{
1183 						if (j>0 && minx<x)
1184 							AddBlockLine(blocklists,blockcount,blockdone,ncols*yb+j-1,i);
1185 					}
1186 				}
1187 				else if (j>0 && minx<x)	// else not at corner: x-,y
1188 					AddBlockLine(blocklists,blockcount,blockdone,ncols*yb+j-1,i);
1189 			}
1190 		}
1191 
1192 		// For each row, see where the line along its bottom edge, which
1193 		// it contains, intersects the Linedef i. Add i to all the corresponding
1194 		// blocklists.
1195 
1196 		if (!horiz)
1197 		{
1198 			for (j=0;j<nrows;j++)
1199 			{
1200 				// intersection of Linedef with y=yorg+(j<<blkshift)
1201 				// (x,y) on Linedef i satisfies: (y-y1)*dx = dy*(x-x1)
1202 				// x = dx*(y-y1)/dy+x1;
1203 
1204 				int y = yorg+(j<<blkshift);		// (x,y) is intersection
1205 				int x = (dx*(y-y1))/dy+x1;
1206 				int xb = (x-xorg)>>blkshift;	// block column number
1207 				int xp = (x-xorg)&blkmask;		// x position within block
1208 
1209 				if (xb<0 || xb>ncols-1)			// outside blockmap, continue
1210 					continue;
1211 
1212 				if (y<miny || y>maxy)			 // line doesn't touch row
1213 					continue;
1214 
1215 				// The cell that contains the intersection point is always added
1216 
1217 				AddBlockLine (blocklists, blockcount, blockdone, ncols*j+xb, i);
1218 
1219 				// if the intersection is at a corner it depends on the slope
1220 				// (and whether the line extends past the intersection) which
1221 				// blocks are hit
1222 
1223 				if (xp==0)			// intersection at a corner
1224 				{
1225 					if (sneg)       //   \ - blocks x,y-, x-,y
1226 					{
1227 						if (j>0 && miny<y)
1228 							AddBlockLine (blocklists, blockcount, blockdone, ncols*(j-1)+xb, i);
1229 						if (xb>0 && minx<x)
1230 							AddBlockLine (blocklists, blockcount, blockdone, ncols*j+xb-1, i);
1231 					}
1232 					else if (vert)  //   | - block x,y-
1233 					{
1234 						if (j>0 && miny<y)
1235 							AddBlockLine (blocklists, blockcount, blockdone, ncols*(j-1)+xb, i);
1236 					}
1237 					else if (spos)  //   / - block x-,y-
1238 					{
1239 						if (xb>0 && j>0 && miny<y)
1240 							AddBlockLine (blocklists, blockcount, blockdone, ncols*(j-1)+xb-1, i);
1241 					}
1242 				}
1243 				else if (j>0 && miny<y) // else not on a corner: x,y-
1244 					AddBlockLine (blocklists, blockcount, blockdone, ncols*(j-1)+xb, i);
1245 			}
1246 		}
1247 	}
1248 
1249 	// Add initial 0 to all blocklists
1250 	// count the total number of lines (and 0's and -1's)
1251 	memset (blockdone, 0, NBlocks*sizeof(int));
1252 	for (i = 0, linetotal = 0; i < NBlocks; i++)
1253 	{
1254 		AddBlockLine (blocklists, blockcount, blockdone, i, 0);
1255 		linetotal += blockcount[i];
1256 	}
1257 
1258 	// Create the blockmap lump
1259 	blockmaplump = (int *)Z_Malloc(sizeof(*blockmaplump) * (4+NBlocks+linetotal), PU_LEVEL, 0);
1260 
1261 	// blockmap header
1262 	//
1263 	// Rjy: P_CreateBlockMap should not initialise bmaporg{x,y} as P_LoadBlockMap
1264 	// does so again, resulting in their being left-shifted by FRACBITS twice.
1265 	//
1266 	// Thus any map having its blockmap built by the engine would have its
1267 	// origin at (0,0) regardless of where the walls and monsters actually are,
1268 	// breaking all collision detection.
1269 	//
1270 	// Instead have P_CreateBlockMap create blockmaplump only, so that both
1271 	// clauses of the conditional in P_LoadBlockMap have the same effect, and
1272 	// bmap* are only initialised from blockmaplump[0..3] once in the latter.
1273 	//
1274 	blockmaplump[0] = xorg;
1275 	blockmaplump[1] = yorg;
1276 	blockmaplump[2] = ncols;
1277 	blockmaplump[3] = nrows;
1278 
1279 	// offsets to lists and block lists
1280 	for (i = 0; i < NBlocks; i++)
1281 	{
1282 		linelist_t *bl = blocklists[i];
1283 		DWORD offs = blockmaplump[4+i] =   // set offset to block's list
1284 			(i? blockmaplump[4+i-1] : 4+NBlocks) + (i? blockcount[i-1] : 0);
1285 
1286 		// add the lines in each block's list to the blockmaplump
1287 		// delete each list node as we go
1288 
1289 		while (bl)
1290 		{
1291 			linelist_t *tmp = bl->next;
1292 			blockmaplump[offs++] = bl->num;
1293 			delete[] bl;
1294 			bl = tmp;
1295 		}
1296 	}
1297 
1298 	// free all temporary storage
1299 	delete[] blocklists;
1300 	delete[] blockcount;
1301 	delete[] blockdone;
1302 }
1303 
1304 // jff 10/6/98
1305 // End new code added to speed up calculation of internal blockmap
1306 
1307 //
1308 // P_LoadBlockMap
1309 //
1310 // [RH] Changed this some
1311 //
P_LoadBlockMap(int lump)1312 void P_LoadBlockMap (int lump)
1313 {
1314 	int count;
1315 
1316 	if (Args.CheckParm("-blockmap") || (count = W_LumpLength(lump)/2) >= 0x10000 || count < 4)
1317 		P_CreateBlockMap();
1318 	else
1319 	{
1320 		short *wadblockmaplump = (short *)W_CacheLumpNum (lump, PU_LEVEL);
1321 		int i;
1322 		blockmaplump = (int *)Z_Malloc(sizeof(*blockmaplump) * count, PU_LEVEL, 0);
1323 
1324 		// killough 3/1/98: Expand wad blockmap into larger internal one,
1325 		// by treating all offsets except -1 as unsigned and zero-extending
1326 		// them. This potentially doubles the size of blockmaps allowed,
1327 		// because Doom originally considered the offsets as always signed.
1328 
1329 		blockmaplump[0] = LESHORT(wadblockmaplump[0]);
1330 		blockmaplump[1] = LESHORT(wadblockmaplump[1]);
1331 		blockmaplump[2] = (DWORD)(LESHORT(wadblockmaplump[2])) & 0xffff;
1332 		blockmaplump[3] = (DWORD)(LESHORT(wadblockmaplump[3])) & 0xffff;
1333 
1334 		for (i=4 ; i<count ; i++)
1335 		{
1336 			short t = LESHORT(wadblockmaplump[i]);          // killough 3/1/98
1337 			blockmaplump[i] = t == -1 ? (DWORD)0xffffffff : (DWORD) t & 0xffff;
1338 		}
1339 
1340 		Z_Free (wadblockmaplump);
1341 	}
1342 
1343 	bmaporgx = blockmaplump[0]<<FRACBITS;
1344 	bmaporgy = blockmaplump[1]<<FRACBITS;
1345 	bmapwidth = blockmaplump[2];
1346 	bmapheight = blockmaplump[3];
1347 
1348 	// clear out mobj chains
1349 	count = sizeof(*blocklinks) * bmapwidth*bmapheight;
1350 	blocklinks = (AActor **)Z_Malloc (count, PU_LEVEL, 0);
1351 	memset (blocklinks, 0, count);
1352 	blockmap = blockmaplump+4;
1353 }
1354 
1355 
1356 
1357 //
1358 // P_GroupLines
1359 // Builds sector line lists and subsector sector numbers.
1360 // Finds block bounding boxes for sectors.
1361 //
P_GroupLines(void)1362 void P_GroupLines (void)
1363 {
1364 	line_t**			linebuffer;
1365 	int 				i;
1366 	int 				j;
1367 	int 				total;
1368 	line_t* 			li;
1369 	sector_t*			sector;
1370 	DBoundingBox		bbox;
1371 	int 				block;
1372 
1373 	// look up sector number for each subsector
1374 	for (i = 0; i < numsubsectors; i++)
1375 	{
1376 		if (subsectors[i].firstline >= (unsigned int)numsegs)
1377 			I_Error("subsector[%d].firstline exceeds numsegs (%u)", i, numsegs);
1378 		subsectors[i].sector = segs[subsectors[i].firstline].sidedef->sector;
1379 	}
1380 
1381 	// count number of lines in each sector
1382 	li = lines;
1383 	total = 0;
1384 	for (i = 0; i < numlines; i++, li++)
1385 	{
1386 		total++;
1387 		if (!li->frontsector && li->backsector)
1388 		{
1389 			// swap front and backsectors if a one-sided linedef
1390 			// does not have a front sector
1391 			li->frontsector = li->backsector;
1392 			li->backsector = NULL;
1393 		}
1394 
1395         if (li->frontsector)
1396             li->frontsector->linecount++;
1397 
1398 		if (li->backsector && li->backsector != li->frontsector)
1399 		{
1400 			li->backsector->linecount++;
1401 			total++;
1402 		}
1403 	}
1404 
1405 	// build line tables for each sector
1406 	linebuffer = (line_t **)Z_Malloc (total*sizeof(line_t *), PU_LEVEL, 0);
1407 	sector = sectors;
1408 	for (i=0 ; i<numsectors ; i++, sector++)
1409 	{
1410 		bbox.ClearBox ();
1411 		sector->lines = linebuffer;
1412 		li = lines;
1413 		for (j=0 ; j<numlines ; j++, li++)
1414 		{
1415 			if (li->frontsector == sector || li->backsector == sector)
1416 			{
1417 				*linebuffer++ = li;
1418 				bbox.AddToBox (li->v1->x, li->v1->y);
1419 				bbox.AddToBox (li->v2->x, li->v2->y);
1420 			}
1421 		}
1422 		if (linebuffer - sector->lines != sector->linecount)
1423 			I_Error ("P_GroupLines: miscounted");
1424 
1425 		// set the soundorg to the middle of the bounding box
1426 		sector->soundorg[0] = (bbox.Right()+bbox.Left())/2;
1427 		sector->soundorg[1] = (bbox.Top()+bbox.Bottom())/2;
1428 
1429 		// adjust bounding box to map blocks
1430 		block = (bbox.Top()-bmaporgy+MAXRADIUS)>>MAPBLOCKSHIFT;
1431 		block = block >= bmapheight ? bmapheight-1 : block;
1432 		sector->blockbox[BOXTOP]=block;
1433 
1434 		block = (bbox.Bottom()-bmaporgy-MAXRADIUS)>>MAPBLOCKSHIFT;
1435 		block = block < 0 ? 0 : block;
1436 		sector->blockbox[BOXBOTTOM]=block;
1437 
1438 		block = (bbox.Right()-bmaporgx+MAXRADIUS)>>MAPBLOCKSHIFT;
1439 		block = block >= bmapwidth ? bmapwidth-1 : block;
1440 		sector->blockbox[BOXRIGHT]=block;
1441 
1442 		block = (bbox.Left()-bmaporgx-MAXRADIUS)>>MAPBLOCKSHIFT;
1443 		block = block < 0 ? 0 : block;
1444 		sector->blockbox[BOXLEFT]=block;
1445 	}
1446 
1447 }
1448 
1449 //
1450 // P_RemoveSlimeTrails()
1451 //
1452 // killough 10/98
1453 //
1454 // Slime trails are inherent to Doom's coordinate system -- i.e. there is
1455 // nothing that a node builder can do to prevent slime trails ALL of the time,
1456 // because it's a product of the integer coodinate system, and just because
1457 // two lines pass through exact integer coordinates, doesn't necessarily mean
1458 // that they will intersect at integer coordinates. Thus we must allow for
1459 // fractional coordinates if we are to be able to split segs with node lines,
1460 // as a node builder must do when creating a BSP tree.
1461 //
1462 // A wad file does not allow fractional coordinates, so node builders are out
1463 // of luck except that they can try to limit the number of splits (they might
1464 // also be able to detect the degree of roundoff error and try to avoid splits
1465 // with a high degree of roundoff error). But we can use fractional coordinates
1466 // here, inside the engine. It's like the difference between square inches and
1467 // square miles, in terms of granularity.
1468 //
1469 // For each vertex of every seg, check to see whether it's also a vertex of
1470 // the linedef associated with the seg (i.e, it's an endpoint). If it's not
1471 // an endpoint, and it wasn't already moved, move the vertex towards the
1472 // linedef by projecting it using the law of cosines. Formula:
1473 //
1474 //      2        2                         2        2
1475 //    dx  x0 + dy  x1 + dx dy (y0 - y1)  dy  y0 + dx  y1 + dx dy (x0 - x1)
1476 //   {---------------------------------, ---------------------------------}
1477 //                  2     2                            2     2
1478 //                dx  + dy                           dx  + dy
1479 //
1480 // (x0,y0) is the vertex being moved, and (x1,y1)-(x1+dx,y1+dy) is the
1481 // reference linedef.
1482 //
1483 // Segs corresponding to orthogonal linedefs (exactly vertical or horizontal
1484 // linedefs), which comprise at least half of all linedefs in most wads, don't
1485 // need to be considered, because they almost never contribute to slime trails
1486 // (because then any roundoff error is parallel to the linedef, which doesn't
1487 // cause slime). Skipping simple orthogonal lines lets the code finish quicker.
1488 //
1489 // Please note: This section of code is not interchangable with TeamTNT's
1490 // code which attempts to fix the same problem.
1491 //
1492 // Firelines (TM) is a Rezistered Trademark of MBF Productions
1493 //
1494 
P_RemoveSlimeTrails()1495 static void P_RemoveSlimeTrails()
1496 {
1497 	byte* hit = (byte *)Z_Malloc(numvertexes, PU_LEVEL, 0);
1498 	memset(hit, 0, numvertexes * sizeof(byte));
1499 
1500 	for (int i = 0; i < numsegs; i++)
1501 	{
1502 		const line_t *l = segs[i].linedef;		// The parent linedef
1503 
1504 		// We can ignore orthogonal lines
1505 		if (l->slopetype != ST_VERTICAL && l->slopetype != ST_HORIZONTAL)
1506 		{
1507 			vertex_t *v = segs[i].v1;
1508 			do
1509 			{
1510 				if (!hit[v - vertexes])				// If we haven't processed vertex
1511 				{
1512 					hit[v - vertexes] = 1;			// Mark this vertex as processed
1513 					if (v != l->v1 && v != l->v2)	// Exclude endpoints of linedefs
1514 					{
1515 						// Project the vertex back onto the parent linedef
1516 						int64_t dx2 = (l->dx >> FRACBITS) * (l->dx >> FRACBITS);
1517 						int64_t dy2 = (l->dy >> FRACBITS) * (l->dy >> FRACBITS);
1518 						int64_t dxy = (l->dx >> FRACBITS) * (l->dy >> FRACBITS);
1519 						int64_t s = dx2 + dy2;
1520 						fixed_t x0 = v->x, y0 = v->y, x1 = l->v1->x, y1 = l->v1->y;
1521 						v->x = (fixed_t)((dx2 * x0 + dy2 * x1 + dxy * (y0 - y1)) / s);
1522 						v->y = (fixed_t)((dy2 * y0 + dx2 * y1 + dxy * (x0 - x1)) / s);
1523 					}
1524 				}  // Obsfucated C contest entry:   :)
1525 			} while ((v != segs[i].v2) && (v = segs[i].v2));
1526 		}
1527 	}
1528 
1529 	Z_Free(hit);
1530 }
1531 
1532 //
1533 // [RH] P_LoadBehavior
1534 //
P_LoadBehavior(int lumpnum)1535 void P_LoadBehavior (int lumpnum)
1536 {
1537 	byte *behavior = (byte *)W_CacheLumpNum (lumpnum, PU_LEVEL);
1538 
1539 	level.behavior = new FBehavior (behavior, lumpinfo[lumpnum].size);
1540 
1541 	if (!level.behavior->IsGood ())
1542 	{
1543 		delete level.behavior;
1544 		level.behavior = NULL;
1545 	}
1546 }
1547 
1548 //
1549 // P_AllocStarts
1550 //
P_AllocStarts(void)1551 void P_AllocStarts(void)
1552 {
1553 	if (!deathmatchstarts)
1554 	{
1555 		MaxDeathmatchStarts = 16;	// [RH] Default. Increased as needed.
1556 		deathmatchstarts = (mapthing2_t *)Malloc (MaxDeathmatchStarts * sizeof(mapthing2_t));
1557 	}
1558 	deathmatch_p = deathmatchstarts;
1559 
1560 	//	[Toke - CTF]
1561 	if (!blueteamstarts) // [Toke - CTF - starts]
1562 	{
1563 		MaxBlueTeamStarts = 16;
1564 		blueteamstarts = (mapthing2_t *)Malloc (MaxBlueTeamStarts * sizeof(mapthing2_t));
1565 	}
1566 	blueteam_p = blueteamstarts;
1567 
1568 	if (!redteamstarts) // [Toke - CTF - starts]
1569 	{
1570 		MaxRedTeamStarts = 16;
1571 		redteamstarts = (mapthing2_t *)Malloc (MaxRedTeamStarts * sizeof(mapthing2_t));
1572 	}
1573 	redteam_p = redteamstarts;
1574 }
1575 
1576 //
1577 // P_SetupLevel
1578 //
1579 extern dyncolormap_t NormalLight;
1580 extern polyblock_t **PolyBlockMap;
1581 
1582 // [RH] position indicates the start spot to spawn at
P_SetupLevel(char * lumpname,int position)1583 void P_SetupLevel (char *lumpname, int position)
1584 {
1585 	size_t lumpnum;
1586 
1587 	level.total_monsters = level.total_items = level.total_secrets =
1588 		level.killed_monsters = level.found_items = level.found_secrets =
1589 		wminfo.maxfrags = 0;
1590 	wminfo.partime = 180;
1591 
1592 	if (!savegamerestore)
1593 	{
1594 		for (Players::iterator it = players.begin();it != players.end();++it)
1595 		{
1596 			it->killcount = it->secretcount = it->itemcount = 0;
1597 		}
1598 	}
1599 
1600 	// Initial height of PointOfView will be set by player think.
1601 	consoleplayer().viewz = 1;
1602 
1603 	// Make sure all sounds are stopped before Z_FreeTags.
1604 	S_Start ();
1605 
1606 	// [RH] Clear all ThingID hash chains.
1607 	AActor::ClearTIDHashes ();
1608 
1609 	// [RH] clear out the mid-screen message
1610 	C_MidPrint (NULL);
1611 
1612 	PolyBlockMap = NULL;
1613 
1614 	DThinker::DestroyAllThinkers ();
1615 	Z_FreeTags (PU_LEVEL, PU_PURGELEVEL-1);
1616 	NormalLight.next = NULL;	// [RH] Z_FreeTags frees all the custom colormaps
1617 
1618 	// UNUSED W_Profile ();
1619 
1620 	// find map num
1621 	lumpnum = W_GetNumForName (lumpname);
1622 
1623 	// [RH] Check if this map is Hexen-style.
1624 	//		LINEDEFS and THINGS need to be handled accordingly.
1625 	//		If it is, we also need to distinguish between projectile cross and hit
1626 	HasBehavior = W_CheckLumpName (lumpnum+ML_BEHAVIOR, "BEHAVIOR");
1627 	//oldshootactivation = !HasBehavior;
1628 
1629 	// note: most of this ordering is important
1630 
1631 	// [RH] Load in the BEHAVIOR lump
1632 	if (level.behavior != NULL)
1633 	{
1634 		delete level.behavior;
1635 		level.behavior = NULL;
1636 	}
1637 	if (HasBehavior)
1638 	{
1639 		P_LoadBehavior (lumpnum+ML_BEHAVIOR);
1640 	}
1641 
1642     level.time = 0;
1643 
1644 	P_LoadVertexes (lumpnum+ML_VERTEXES);
1645 	P_LoadSectors (lumpnum+ML_SECTORS);
1646 	P_LoadSideDefs (lumpnum+ML_SIDEDEFS);
1647 	if (!HasBehavior)
1648 		P_LoadLineDefs (lumpnum+ML_LINEDEFS);
1649 	else
1650 		P_LoadLineDefs2 (lumpnum+ML_LINEDEFS);	// [RH] Load Hexen-style linedefs
1651 	P_LoadSideDefs2 (lumpnum+ML_SIDEDEFS);
1652 	P_FinishLoadingLineDefs ();
1653 	P_LoadBlockMap (lumpnum+ML_BLOCKMAP);
1654 
1655 	if (!P_LoadXNOD(lumpnum+ML_NODES))
1656 	{
1657 		P_LoadSubsectors (lumpnum+ML_SSECTORS);
1658 		P_LoadNodes (lumpnum+ML_NODES);
1659 		P_LoadSegs (lumpnum+ML_SEGS);
1660 	}
1661 
1662 	rejectmatrix = (byte *)W_CacheLumpNum (lumpnum+ML_REJECT, PU_LEVEL);
1663 	{
1664 		// [SL] 2011-07-01 - Check to see if the reject table is of the proper size
1665 		// If it's too short, the reject table should be ignored when
1666 		// calling P_CheckSight
1667 		if (W_LumpLength(lumpnum + ML_REJECT) < ((unsigned int)ceil((float)(numsectors * numsectors / 8))))
1668 		{
1669 			DPrintf("Reject matrix is not valid and will be ignored.\n");
1670 			rejectempty = true;
1671 		}
1672 	}
1673 	P_GroupLines ();
1674 
1675 	// [SL] don't move seg vertices if compatibility is cruical
1676 	if (!demoplayback && !demorecording)
1677 		P_RemoveSlimeTrails();
1678 
1679 	P_SetupSlopes();
1680 
1681     po_NumPolyobjs = 0;
1682 
1683 	P_AllocStarts();
1684 
1685 	if (!HasBehavior)
1686 		P_LoadThings (lumpnum+ML_THINGS);
1687 	else
1688 		P_LoadThings2 (lumpnum+ML_THINGS, position);	// [RH] Load Hexen-style things
1689 
1690 	if (!HasBehavior)
1691 		P_TranslateTeleportThings ();	// [RH] Assign teleport destination TIDs
1692 
1693     PO_Init ();
1694 
1695     if (serverside)
1696     {
1697 		for (Players::iterator it = players.begin();it != players.end();++it)
1698 		{
1699 			SV_PreservePlayer(*it);
1700 
1701 			if (it->ingame())
1702 			{
1703 				// if deathmatch, randomly spawn the active players
1704 				// denis - this function checks for deathmatch internally
1705 				G_DeathMatchSpawnPlayer(*it);
1706 			}
1707 		}
1708     }
1709 
1710 	// clear special respawning que
1711 	iquehead = iquetail = 0;
1712 
1713 	// killough 3/26/98: Spawn icon landings:
1714 	P_SpawnBrainTargets();
1715 
1716 	// set up world state
1717 	P_SpawnSpecials ();
1718 
1719 	// build subsector connect matrix
1720 	//	UNUSED P_ConnectSubsectors ();
1721 
1722 	R_OldBlend = ~0;
1723 
1724 	// preload graphics
1725 	if (clientside && precache)
1726 		R_PrecacheLevel ();
1727 }
1728 
1729 //
1730 // P_Init
1731 //
P_Init(void)1732 void P_Init (void)
1733 {
1734 	P_InitSwitchList ();
1735 	P_InitPicAnims ();
1736 	R_InitSprites (sprnames);
1737 }
1738 
1739 
1740 // [ML] Do stuff when the timelimit is reset
1741 // Where else can I put this??
CVAR_FUNC_IMPL(sv_timelimit)1742 CVAR_FUNC_IMPL(sv_timelimit)
1743 {
1744 	level.timeleft = var * TICRATE * 60;
1745 }
1746 
CVAR_FUNC_IMPL(sv_intermissionlimit)1747 CVAR_FUNC_IMPL(sv_intermissionlimit)
1748 {
1749 	level.inttimeleft = (var < 1 ? DEFINTSECS : var);
1750 }
1751 
1752 
P_SetupLevelFloorPlane(sector_t * sector)1753 static void P_SetupLevelFloorPlane(sector_t *sector)
1754 {
1755 	if (!sector)
1756 		return;
1757 
1758 	sector->floorplane.a = sector->floorplane.b = 0;
1759 	sector->floorplane.c = sector->floorplane.invc = FRACUNIT;
1760 	sector->floorplane.d = -sector->floorheight;
1761 	sector->floorplane.texx = sector->floorplane.texy = 0;
1762 	sector->floorplane.sector = sector;
1763 }
1764 
P_SetupLevelCeilingPlane(sector_t * sector)1765 static void P_SetupLevelCeilingPlane(sector_t *sector)
1766 {
1767 	if (!sector)
1768 		return;
1769 
1770 	sector->ceilingplane.a = sector->ceilingplane.b = 0;
1771 	sector->ceilingplane.c = sector->ceilingplane.invc = -FRACUNIT;
1772 	sector->ceilingplane.d = sector->ceilingheight;
1773 	sector->ceilingplane.texx = sector->ceilingplane.texy = 0;
1774 	sector->ceilingplane.sector = sector;
1775 }
1776 
1777 //
1778 // P_SetupPlane()
1779 //
1780 // Takes a line with the special property Plane_Align and its facing sector
1781 // and calculates the planar equation for the slope formed by the floor or
1782 // ceiling of this sector.  The equation coefficients are stored in a plane_t
1783 // structure and saved either to the sector's ceilingplan or floorplane.
1784 //
P_SetupPlane(sector_t * sec,line_t * line,bool floor)1785 void P_SetupPlane(sector_t* sec, line_t* line, bool floor)
1786 {
1787 	if (!sec || !line || !line->backsector)
1788 		return;
1789 
1790 	// Find the vertex comprising the sector that is farthest from the
1791 	// slope's reference line
1792 
1793 	int bestdist = 0;
1794 	line_t** probe = sec->lines;
1795 	vertex_t *refvert = (*sec->lines)->v1;
1796 
1797 	for (int i = sec->linecount*2; i > 0; i--)
1798 	{
1799 		int dist;
1800 		vertex_t *vert;
1801 
1802 		// Do calculations with only the upper bits, because the lower ones
1803 		// are all zero, and we would overflow for a lot of distances if we
1804 		// kept them around.
1805 
1806 		if (i & 1)
1807 			vert = (*probe++)->v2;
1808 		else
1809 			vert = (*probe)->v1;
1810 		dist = abs (((line->v1->y - vert->y) >> FRACBITS) * (line->dx >> FRACBITS) -
1811 					((line->v1->x - vert->x) >> FRACBITS) * (line->dy >> FRACBITS));
1812 
1813 		if (dist > bestdist)
1814 		{
1815 			bestdist = dist;
1816 			refvert = vert;
1817 		}
1818 	}
1819 
1820 	const sector_t* refsec = line->frontsector == sec ? line->backsector : line->frontsector;
1821 	plane_t* srcplane = floor ? &sec->floorplane : &sec->ceilingplane;
1822 	fixed_t srcheight = floor ? sec->floorheight : sec->ceilingheight;
1823 	fixed_t destheight = floor ? refsec->floorheight : refsec->ceilingheight;
1824 
1825 	v3float_t p, v1, v2, cross;
1826 	M_SetVec3f(&p, line->v1->x, line->v1->y, destheight);
1827 	M_SetVec3f(&v1, line->dx, line->dy, 0);
1828 	M_SetVec3f(&v2, refvert->x - line->v1->x, refvert->y - line->v1->y, srcheight - destheight);
1829 
1830 	M_CrossProductVec3f(&cross, &v1, &v2);
1831 	M_NormalizeVec3f(&cross, &cross);
1832 
1833 	// Fix backward normals
1834 	if ((cross.z < 0 && floor == true) || (cross.z > 0 && floor == false))
1835 	{
1836 		cross.x = -cross.x;
1837 		cross.y = -cross.y;
1838 		cross.z = -cross.z;
1839 	}
1840 
1841 	srcplane->a = FLOAT2FIXED(cross.x);
1842 	srcplane->b = FLOAT2FIXED(cross.y);
1843 	srcplane->c = FLOAT2FIXED(cross.z);
1844 	srcplane->invc = FLOAT2FIXED(1.f/cross.z);
1845 	srcplane->d = -FixedMul(srcplane->a, line->v1->x) - FixedMul(srcplane->b, line->v1->y) - FixedMul(srcplane->c, destheight);
1846 	srcplane->texx = refvert->x;
1847 	srcplane->texy = refvert->y;
1848 }
1849 
P_SetupSlopes()1850 static void P_SetupSlopes()
1851 {
1852 	for (int i = 0; i < numlines; i++)
1853 	{
1854 		line_t *line = &lines[i];
1855 
1856 		if (line->special == Plane_Align)
1857 		{
1858 			line->special = 0;
1859 			line->id = line->args[2];
1860 
1861 			// Floor plane?
1862 			int align_side = line->args[0] & 3;
1863 			if (align_side == 1)
1864 				P_SetupPlane(line->frontsector, line, true);
1865 			else if (align_side == 2)
1866 				P_SetupPlane(line->backsector, line, true);
1867 
1868 			// Ceiling plane?
1869 			align_side = line->args[1] & 3;
1870 			if (align_side == 0)
1871 				align_side = (line->args[0] >> 2) & 3;
1872 
1873 			if (align_side == 1)
1874 				P_SetupPlane(line->frontsector, line, false);
1875 			else if (align_side == 2)
1876 				P_SetupPlane(line->backsector, line, false);
1877 		}
1878 	}
1879 }
1880 
1881 
1882 VERSION_CONTROL (p_setup_cpp, "$Id: p_setup.cpp 4542 2014-02-09 17:39:42Z dr_sean $")
1883 
1884