]> icculus.org git repositories - theoddone33/hhexen.git/blob - base/p_setup.c
Remove obnoxious documentation files
[theoddone33/hhexen.git] / base / p_setup.c
1
2 //**************************************************************************
3 //**
4 //** p_setup.c : Heretic 2 : Raven Software, Corp.
5 //**
6 //** $RCSfile$
7 //** $Revision$
8 //** $Date$
9 //** $Author$
10 //**
11 //**************************************************************************
12
13 // HEADER FILES ------------------------------------------------------------
14
15 #include <math.h>
16 #include <stdlib.h>
17 #include "h2def.h"
18 #include "p_local.h"
19 #include "soundst.h"
20 #ifdef RENDER3D
21 #include "ogl_def.h"
22 float AccurateDistance(fixed_t dx,fixed_t dy);
23 #endif
24
25
26 // MACROS ------------------------------------------------------------------
27
28 #define MAPINFO_SCRIPT_NAME "MAPINFO"
29 #define MCMD_SKY1 1
30 #define MCMD_SKY2 2
31 #define MCMD_LIGHTNING 3
32 #define MCMD_FADETABLE 4
33 #define MCMD_DOUBLESKY 5
34 #define MCMD_CLUSTER 6
35 #define MCMD_WARPTRANS 7
36 #define MCMD_NEXT 8
37 #define MCMD_CDTRACK 9
38 #define MCMD_CD_STARTTRACK 10
39 #define MCMD_CD_END1TRACK 11
40 #define MCMD_CD_END2TRACK 12
41 #define MCMD_CD_END3TRACK 13
42 #define MCMD_CD_INTERTRACK 14
43 #define MCMD_CD_TITLETRACK 15
44
45 #define UNKNOWN_MAP_NAME "DEVELOPMENT MAP"
46 #define DEFAULT_SKY_NAME "SKY1"         // "SKY1" not in demo wad - KR
47 #define DEFAULT_SONG_LUMP "DEFSONG"
48 #define DEFAULT_FADE_TABLE "COLORMAP"
49
50 // TYPES -------------------------------------------------------------------
51
52 typedef struct mapInfo_s mapInfo_t;
53 struct mapInfo_s
54 {
55         short cluster;
56         short warpTrans;
57         short nextMap;
58         short cdTrack;
59         char name[32];
60         short sky1Texture;
61         short sky2Texture;
62         fixed_t sky1ScrollDelta;
63         fixed_t sky2ScrollDelta;
64         boolean doubleSky;
65         boolean lightning;
66         int fadetable;
67         char songLump[10];
68 };
69
70 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
71
72 void P_SpawnMapThing(mapthing_t *mthing);
73
74 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
75
76 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
77
78 static int QualifyMap(int map);
79
80 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
81
82 // PUBLIC DATA DEFINITIONS -------------------------------------------------
83
84 int MapCount;
85 mapthing_t deathmatchstarts[MAXDEATHMATCHSTARTS], *deathmatch_p;
86 mapthing_t playerstarts[MAX_PLAYER_STARTS][MAXPLAYERS];
87 int numvertexes;
88 vertex_t *vertexes;
89 int numsegs;
90 seg_t *segs;
91 int numsectors;
92 sector_t *sectors;
93 int numsubsectors;
94 subsector_t *subsectors;
95 int numnodes;
96 node_t *nodes;
97 int numlines;
98 line_t *lines;
99 int numsides;
100 side_t *sides;
101 short *blockmaplump; // offsets in blockmap are from here
102 short *blockmap;
103 int bmapwidth, bmapheight; // in mapblocks
104 fixed_t bmaporgx, bmaporgy; // origin of block map
105 mobj_t **blocklinks; // for thing chains
106 byte *rejectmatrix; // for fast sight rejection
107
108 // PRIVATE DATA DEFINITIONS ------------------------------------------------
109
110 static mapInfo_t MapInfo[99];
111 static char *MapCmdNames[] =
112 {
113         "SKY1",
114         "SKY2",
115         "DOUBLESKY",
116         "LIGHTNING",
117         "FADETABLE",
118         "CLUSTER",
119         "WARPTRANS",
120         "NEXT",
121         "CDTRACK",
122         "CD_START_TRACK",
123         "CD_END1_TRACK",
124         "CD_END2_TRACK",
125         "CD_END3_TRACK",
126         "CD_INTERMISSION_TRACK",
127         "CD_TITLE_TRACK",
128         NULL
129 };
130 static int MapCmdIDs[] =
131 {
132         MCMD_SKY1,
133         MCMD_SKY2,
134         MCMD_DOUBLESKY,
135         MCMD_LIGHTNING,
136         MCMD_FADETABLE,
137         MCMD_CLUSTER,
138         MCMD_WARPTRANS,
139         MCMD_NEXT,
140         MCMD_CDTRACK,
141         MCMD_CD_STARTTRACK,
142         MCMD_CD_END1TRACK,
143         MCMD_CD_END2TRACK,
144         MCMD_CD_END3TRACK,
145         MCMD_CD_INTERTRACK,
146         MCMD_CD_TITLETRACK
147 };
148
149 static int cd_NonLevelTracks[6]; // Non-level specific song cd track numbers 
150
151 // CODE --------------------------------------------------------------------
152
153 /*
154 =================
155 =
156 = P_LoadVertexes
157 =
158 =================
159 */
160
161 void P_LoadVertexes (int lump)
162 {
163         byte            *data;
164         int                     i;
165         mapvertex_t     *ml;
166         vertex_t        *li;
167
168         numvertexes = W_LumpLength (lump) / sizeof(mapvertex_t);
169         vertexes = Z_Malloc (numvertexes*sizeof(vertex_t),PU_LEVEL,0);
170         data = W_CacheLumpNum (lump,PU_STATIC);
171
172         ml = (mapvertex_t *)data;
173         li = vertexes;
174         for (i=0 ; i<numvertexes ; i++, li++, ml++)
175         {
176                 li->x = SHORT(ml->x)<<FRACBITS;
177                 li->y = SHORT(ml->y)<<FRACBITS;
178         }
179
180         Z_Free (data);
181 }
182
183
184 /*
185 =================
186 =
187 = P_LoadSegs
188 =
189 =================
190 */
191
192 void P_LoadSegs (int lump)
193 {
194         byte            *data;
195         int                     i;
196         mapseg_t        *ml;
197         seg_t           *li;
198         line_t  *ldef;
199         int                     _linedef, side;
200
201         numsegs = W_LumpLength (lump) / sizeof(mapseg_t);
202         segs = Z_Malloc (numsegs*sizeof(seg_t),PU_LEVEL,0);
203         memset (segs, 0, numsegs*sizeof(seg_t));
204         data = W_CacheLumpNum (lump,PU_STATIC);
205
206         ml = (mapseg_t *)data;
207         li = segs;
208         for (i=0 ; i<numsegs ; i++, li++, ml++)
209         {
210                 li->v1 = &vertexes[SHORT(ml->v1)];
211                 li->v2 = &vertexes[SHORT(ml->v2)];
212
213                 li->angle = (SHORT(ml->angle))<<16;
214                 li->offset = (SHORT(ml->offset))<<16;
215                 _linedef = SHORT(ml->linedef);
216                 ldef = &lines[_linedef];
217                 li->linedef = ldef;
218                 side = SHORT(ml->side);
219                 li->sidedef = &sides[ldef->sidenum[side]];
220                 li->frontsector = sides[ldef->sidenum[side]].sector;
221                 if (ldef-> flags & ML_TWOSIDED)
222                         li->backsector = sides[ldef->sidenum[side^1]].sector;
223                 else
224                         li->backsector = 0;
225
226 #ifdef RENDER3D
227         // Calculate the length of the segment. We need this for
228         // the texture coordinates. -jk
229         li->len = AccurateDistance( li->v2->x - li->v1->x,
230                                     li->v2->y - li->v1->y );
231 #endif
232         }
233
234         Z_Free (data);
235 }
236
237
238 /*
239 =================
240 =
241 = P_LoadSubsectors
242 =
243 =================
244 */
245
246 void P_LoadSubsectors (int lump)
247 {
248         byte                    *data;
249         int                             i;
250         mapsubsector_t  *ms;
251         subsector_t             *ss;
252
253         numsubsectors = W_LumpLength (lump) / sizeof(mapsubsector_t);
254         subsectors = Z_Malloc (numsubsectors*sizeof(subsector_t),PU_LEVEL,0);
255         data = W_CacheLumpNum (lump,PU_STATIC);
256
257         ms = (mapsubsector_t *)data;
258         memset (subsectors,0, numsubsectors*sizeof(subsector_t));
259         ss = subsectors;
260         for (i=0 ; i<numsubsectors ; i++, ss++, ms++)
261         {
262                 ss->numlines = SHORT(ms->numsegs);
263                 ss->firstline = SHORT(ms->firstseg);
264         }
265
266         Z_Free (data);
267 }
268
269
270 /*
271 =================
272 =
273 = P_LoadSectors
274 =
275 =================
276 */
277
278 void P_LoadSectors (int lump)
279 {
280         byte                    *data;
281         int                             i;
282         mapsector_t             *ms;
283         sector_t                *ss;
284
285         numsectors = W_LumpLength (lump) / sizeof(mapsector_t);
286         sectors = Z_Malloc (numsectors*sizeof(sector_t),PU_LEVEL,0);
287         memset (sectors, 0, numsectors*sizeof(sector_t));
288         data = W_CacheLumpNum (lump,PU_STATIC);
289
290         ms = (mapsector_t *)data;
291         ss = sectors;
292
293         // Make sure primary lumps are used for flat searching
294         W_UsePrimary();
295
296         for(i = 0; i < numsectors; i++, ss++, ms++)
297         {
298                 ss->floorheight = SHORT(ms->floorheight)<<FRACBITS;
299                 ss->ceilingheight = SHORT(ms->ceilingheight)<<FRACBITS;
300                 ss->floorpic = R_FlatNumForName(ms->floorpic);
301                 ss->ceilingpic = R_FlatNumForName(ms->ceilingpic);
302                 ss->lightlevel = SHORT(ms->lightlevel);
303                 ss->special = SHORT(ms->special);
304                 ss->tag = SHORT(ms->tag);
305                 ss->thinglist = NULL;
306                 ss->seqType = SEQTYPE_STONE; // default seqType
307
308 #ifdef RENDER3D
309         ss->flatoffx = ss->flatoffy = 0;    // Flat scrolling.
310         ss->skyfix = 0;     // Set if needed.
311 #endif
312         }
313         if(DevMaps)
314         {
315                 W_UseAuxiliary();
316         }
317         Z_Free(data);
318 }
319
320
321 /*
322 =================
323 =
324 = P_LoadNodes
325 =
326 =================
327 */
328
329 void P_LoadNodes (int lump)
330 {
331         byte            *data;
332         int                     i,j,k;
333         mapnode_t       *mn;
334         node_t          *no;
335
336         numnodes = W_LumpLength (lump) / sizeof(mapnode_t);
337         nodes = Z_Malloc (numnodes*sizeof(node_t),PU_LEVEL,0);
338         data = W_CacheLumpNum (lump,PU_STATIC);
339
340         mn = (mapnode_t *)data;
341         no = nodes;
342         for (i=0 ; i<numnodes ; i++, no++, mn++)
343         {
344                 no->x = SHORT(mn->x)<<FRACBITS;
345                 no->y = SHORT(mn->y)<<FRACBITS;
346                 no->dx = SHORT(mn->dx)<<FRACBITS;
347                 no->dy = SHORT(mn->dy)<<FRACBITS;
348                 for (j=0 ; j<2 ; j++)
349                 {
350                         no->children[j] = SHORT(mn->children[j]);
351                         for (k=0 ; k<4 ; k++)
352                                 no->bbox[j][k] = SHORT(mn->bbox[j][k])<<FRACBITS;
353                 }
354         }
355         Z_Free (data);
356 }
357
358 //==========================================================================
359 //
360 // P_LoadThings
361 //
362 //==========================================================================
363
364 void P_LoadThings(int lump)
365 {
366         byte *data;
367         int i;
368         mapthing_t *mt;
369         int numthings;
370         int playerCount;
371         int deathSpotsCount;
372
373         data = W_CacheLumpNum(lump, PU_STATIC);
374         numthings = W_LumpLength(lump)/sizeof(mapthing_t);
375
376         mt = (mapthing_t *)data;
377         for(i = 0; i < numthings; i++, mt++)
378         {
379                 mt->tid = SHORT(mt->tid);
380                 mt->x = SHORT(mt->x);
381                 mt->y = SHORT(mt->y);
382                 mt->height = SHORT(mt->height);
383                 mt->angle = SHORT(mt->angle);
384                 mt->type = SHORT(mt->type);
385                 mt->options = SHORT(mt->options);
386                 P_SpawnMapThing(mt);
387         }
388         P_CreateTIDList();
389         P_InitCreatureCorpseQueue(false); // false = do NOT scan for corpses
390         Z_Free(data);
391
392         if(!deathmatch)
393         { // Don't need to check deathmatch spots
394                 return;
395         }
396         playerCount = 0;
397         for(i = 0; i < MAXPLAYERS; i++)
398         {
399                 playerCount += playeringame[i];
400         }
401         deathSpotsCount = deathmatch_p-deathmatchstarts;
402         if(deathSpotsCount < playerCount)
403         {
404                 I_Error("P_LoadThings: Player count (%d) exceeds deathmatch "
405                         "spots (%d)", playerCount, deathSpotsCount);
406         }
407 }
408
409 /*
410 =================
411 =
412 = P_LoadLineDefs
413 =
414 =================
415 */
416
417 void P_LoadLineDefs(int lump)
418 {
419         byte *data;
420         int i;
421         maplinedef_t *mld;
422         line_t *ld;
423         vertex_t *v1, *v2;
424
425         numlines = W_LumpLength(lump)/sizeof(maplinedef_t);
426         lines = Z_Malloc(numlines*sizeof(line_t), PU_LEVEL, 0);
427         memset(lines, 0, numlines*sizeof(line_t));
428         data = W_CacheLumpNum(lump, PU_STATIC);
429
430         mld = (maplinedef_t *)data;
431         ld = lines;
432         for(i = 0; i < numlines; i++, mld++, ld++)
433         {
434                 ld->flags = SHORT(mld->flags);
435
436                 // Old line special info ...
437                 //ld->special = SHORT(mld->special);
438                 //ld->tag = SHORT(mld->tag);
439
440                 // New line special info ...
441                 ld->special = mld->special;
442                 ld->arg1 = mld->arg1;
443                 ld->arg2 = mld->arg2;
444                 ld->arg3 = mld->arg3;
445                 ld->arg4 = mld->arg4;
446                 ld->arg5 = mld->arg5;
447
448                 v1 = ld->v1 = &vertexes[SHORT(mld->v1)];
449                 v2 = ld->v2 = &vertexes[SHORT(mld->v2)];
450                 ld->dx = v2->x - v1->x;
451                 ld->dy = v2->y - v1->y;
452                 if (!ld->dx)
453                         ld->slopetype = ST_VERTICAL;
454                 else if (!ld->dy)
455                         ld->slopetype = ST_HORIZONTAL;
456                 else
457                 {
458                         if (FixedDiv (ld->dy , ld->dx) > 0)
459                                 ld->slopetype = ST_POSITIVE;
460                         else
461                                 ld->slopetype = ST_NEGATIVE;
462                 }
463
464                 if (v1->x < v2->x)
465                 {
466                         ld->bbox[BOXLEFT] = v1->x;
467                         ld->bbox[BOXRIGHT] = v2->x;
468                 }
469                 else
470                 {
471                         ld->bbox[BOXLEFT] = v2->x;
472                         ld->bbox[BOXRIGHT] = v1->x;
473                 }
474                 if (v1->y < v2->y)
475                 {
476                         ld->bbox[BOXBOTTOM] = v1->y;
477                         ld->bbox[BOXTOP] = v2->y;
478                 }
479                 else
480                 {
481                         ld->bbox[BOXBOTTOM] = v2->y;
482                         ld->bbox[BOXTOP] = v1->y;
483                 }
484                 ld->sidenum[0] = SHORT(mld->sidenum[0]);
485                 ld->sidenum[1] = SHORT(mld->sidenum[1]);
486                 if (ld->sidenum[0] != -1)
487                         ld->frontsector = sides[ld->sidenum[0]].sector;
488                 else
489                         ld->frontsector = 0;
490                 if (ld->sidenum[1] != -1)
491                         ld->backsector = sides[ld->sidenum[1]].sector;
492                 else
493                         ld->backsector = 0;
494         }
495
496         Z_Free (data);
497 }
498
499
500 /*
501 =================
502 =
503 = P_LoadSideDefs
504 =
505 =================
506 */
507
508 void P_LoadSideDefs (int lump)
509 {
510         byte                    *data;
511         int                             i;
512         mapsidedef_t    *msd;
513         side_t                  *sd;
514
515         numsides = W_LumpLength (lump) / sizeof(mapsidedef_t);
516         sides = Z_Malloc (numsides*sizeof(side_t),PU_LEVEL,0);
517         memset (sides, 0, numsides*sizeof(side_t));
518         data = W_CacheLumpNum (lump,PU_STATIC);
519
520         msd = (mapsidedef_t *)data;
521         sd = sides;
522
523         // Make sure primary lumps are used for texture searching
524         W_UsePrimary();
525
526         for(i = 0; i < numsides; i++, msd++, sd++)
527         {
528                 sd->textureoffset = SHORT(msd->textureoffset)<<FRACBITS;
529                 sd->rowoffset = SHORT(msd->rowoffset)<<FRACBITS;
530                 sd->toptexture = R_TextureNumForName(msd->toptexture);
531                 sd->bottomtexture = R_TextureNumForName(msd->bottomtexture);
532                 sd->midtexture = R_TextureNumForName(msd->midtexture);
533                 sd->sector = &sectors[SHORT(msd->sector)];
534         }
535         if(DevMaps)
536         {
537                 W_UseAuxiliary();
538         }
539         Z_Free(data);
540 }
541
542 /*
543 =================
544 =
545 = P_LoadBlockMap
546 =
547 =================
548 */
549
550 void P_LoadBlockMap (int lump)
551 {
552         int             i, count;
553
554         blockmaplump = W_CacheLumpNum (lump,PU_LEVEL);
555         blockmap = blockmaplump+4;
556         count = W_LumpLength (lump)/2;
557         for (i=0 ; i<count ; i++)
558                 blockmaplump[i] = SHORT(blockmaplump[i]);
559
560         bmaporgx = blockmaplump[0]<<FRACBITS;
561         bmaporgy = blockmaplump[1]<<FRACBITS;
562         bmapwidth = blockmaplump[2];
563         bmapheight = blockmaplump[3];
564
565 // clear out mobj chains
566         count = sizeof(*blocklinks)* bmapwidth*bmapheight;
567         blocklinks = Z_Malloc (count,PU_LEVEL, 0);
568         memset (blocklinks, 0, count);
569 }
570
571
572
573
574 /*
575 =================
576 =
577 = P_GroupLines
578 =
579 = Builds sector line lists and subsector sector numbers
580 = Finds block bounding boxes for sectors
581 =================
582 */
583
584 void P_GroupLines (void)
585 {
586         line_t          **linebuffer;
587         int                     i, j, total;
588         line_t          *li;
589         sector_t        *sector;
590         subsector_t     *ss;
591         seg_t           *seg;
592         fixed_t         bbox[4];
593         int                     block;
594
595 // look up sector number for each subsector
596         ss = subsectors;
597         for (i=0 ; i<numsubsectors ; i++, ss++)
598         {
599                 seg = &segs[ss->firstline];
600                 ss->sector = seg->sidedef->sector;
601         }
602
603 // count number of lines in each sector
604         li = lines;
605         total = 0;
606         for (i=0 ; i<numlines ; i++, li++)
607         {
608                 total++;
609                 li->frontsector->linecount++;
610                 if (li->backsector && li->backsector != li->frontsector)
611                 {
612                         li->backsector->linecount++;
613                         total++;
614                 }
615         }
616
617 // build line tables for each sector
618         linebuffer = Z_Malloc (total*4, PU_LEVEL, 0);
619         sector = sectors;
620         for (i=0 ; i<numsectors ; i++, sector++)
621         {
622                 M_ClearBox (bbox);
623                 sector->lines = linebuffer;
624                 li = lines;
625                 for (j=0 ; j<numlines ; j++, li++)
626                 {
627                         if (li->frontsector == sector || li->backsector == sector)
628                         {
629                                 *linebuffer++ = li;
630                                 M_AddToBox (bbox, li->v1->x, li->v1->y);
631                                 M_AddToBox (bbox, li->v2->x, li->v2->y);
632                         }
633                 }
634                 if (linebuffer - sector->lines != sector->linecount)
635                         I_Error ("P_GroupLines: miscounted");
636
637                 // set the degenmobj_t to the middle of the bounding box
638                 sector->soundorg.x = (bbox[BOXRIGHT]+bbox[BOXLEFT])/2;
639                 sector->soundorg.y = (bbox[BOXTOP]+bbox[BOXBOTTOM])/2;
640
641                 // adjust bounding box to map blocks
642                 block = (bbox[BOXTOP]-bmaporgy+MAXRADIUS)>>MAPBLOCKSHIFT;
643                 block = block >= bmapheight ? bmapheight-1 : block;
644                 sector->blockbox[BOXTOP]=block;
645
646                 block = (bbox[BOXBOTTOM]-bmaporgy-MAXRADIUS)>>MAPBLOCKSHIFT;
647                 block = block < 0 ? 0 : block;
648                 sector->blockbox[BOXBOTTOM]=block;
649
650                 block = (bbox[BOXRIGHT]-bmaporgx+MAXRADIUS)>>MAPBLOCKSHIFT;
651                 block = block >= bmapwidth ? bmapwidth-1 : block;
652                 sector->blockbox[BOXRIGHT]=block;
653
654                 block = (bbox[BOXLEFT]-bmaporgx-MAXRADIUS)>>MAPBLOCKSHIFT;
655                 block = block < 0 ? 0 : block;
656                 sector->blockbox[BOXLEFT]=block;
657         }
658
659 }
660
661
662 #ifdef RENDER3D
663 float AccurateDistance(fixed_t dx,fixed_t dy)
664 {
665     float fx = FIX2FLT(dx), fy = FIX2FLT(dy);
666          
667     return (float)sqrt(fx*fx + fy*fy);
668 }
669
670
671 #define MAX_CC_SIDES    64
672
673 int detSideFloat(fvertex_t *pnt, fdivline_t *dline)
674 {
675 /*
676             (AY-CY)(BX-AX)-(AX-CX)(BY-AY)
677         s = -----------------------------
678                         L**2
679  
680     If s<0      C is left of AB (you can just check the numerator)
681     If s>0      C is right of AB
682     If s=0      C is on AB
683 */
684     // We'll return false if the point c is on the left side.
685 /*  float ax = FIX2FLT(a->x), ay = FIX2FLT(a->y);
686     float bx = FIX2FLT(b->x), by = FIX2FLT(b->y);
687     float cx = FIX2FLT(c->x), cy = FIX2FLT(c->y);*/
688     //float ax = dline->x, ay = dline->y;
689     //float bx = ax + dline->dx, by = ay + dline->dy;
690  
691     // REWRITE using dline->dx and dline->dy for (bx-ax) and (by-ay).
692  
693     //float s = /*(*/(ay-pnt->y)*(bx-ax)-(ax-pnt->x)*(by-ay);//)/l2;
694     float s = (dline->y-pnt->y)*dline->dx-(dline->x-pnt->x)*dline->dy;
695  
696     if(s<0) return 0;
697     return 1;                                                                   
698 }
699
700
701 // Lines start-end and fdiv must intersect.
702 float findIntersectionVertex( fvertex_t *start, fvertex_t *end,
703                               fdivline_t *fdiv, fvertex_t *inter )
704 {
705     float ax = start->x, ay = start->y, bx = end->x, by = end->y;
706     float cx = fdiv->x, cy = fdiv->y, dx = cx+fdiv->dx, dy = cy+fdiv->dy;
707  
708     /*
709             (YA-YC)(XD-XC)-(XA-XC)(YD-YC)
710         r = -----------------------------  (eqn 1)
711             (XB-XA)(YD-YC)-(YB-YA)(XD-XC)
712     */
713  
714     float r = ((ay-cy)*(dx-cx)-(ax-cx)*(dy-cy)) /
715               ((bx-ax)*(dy-cy)-(by-ay)*(dx-cx));
716     /*
717         XI=XA+r(XB-XA)
718         YI=YA+r(YB-YA)
719     */
720     inter->x = ax + r*(bx-ax);
721     inter->y = ay + r*(by-ay);
722     return r;
723 }
724
725
726 void P_ConvexCarver(subsector_t *ssec, int num, divline_t *list)
727 {
728     //extern void OGL_DrawEdges(int num,fvertex_t *list,int,fdivline_t*,int);
729  
730     int         numclippers = num+ssec->numlines;
731     fdivline_t  *clippers = (fdivline_t*)malloc(numclippers*sizeof(fdivline_t));
732     int         i, k, numedgepoints;
733     fvertex_t   *edgepoints;
734     unsigned char sidelist[MAX_CC_SIDES];
735 #ifndef RENDER3D
736     float       cenx, ceny;
737 #endif
738  
739     // Convert the divlines to float, in reverse order.
740     //printf( "%d clippers (%d pls, %d
741     //segs):\n",numclippers,num,ssec->numlines);
742     for(i=0; i<numclippers; i++)
743     {
744         if(i<num)
745         {
746             clippers[i].x = FIX2FLT(list[num-i-1].x);
747             clippers[i].y = FIX2FLT(list[num-i-1].y);
748             clippers[i].dx = FIX2FLT(list[num-i-1].dx);
749             clippers[i].dy = FIX2FLT(list[num-i-1].dy);
750         }
751         else
752         {
753             seg_t *seg = segs+(ssec->firstline+i-num);
754             clippers[i].x = FIX2FLT(seg->v1->x);
755             clippers[i].y = FIX2FLT(seg->v1->y);
756             clippers[i].dx = FIX2FLT(seg->v2->x - seg->v1->x);
757             clippers[i].dy = FIX2FLT(seg->v2->y - seg->v1->y);
758         }
759         //printf( "  %d: x=%f y=%f dx=%f
760         //dy=%f\n",i,clippers[i].x,clippers[i].y,clippers[i].dx,clippers[i].dy);
761     }
762     //printf( "\n");
763
764     // Setup the 'worldwide' polygon.
765     numedgepoints = 4;
766     edgepoints = (fvertex_t*)malloc(numedgepoints*sizeof(fvertex_t));
767  
768     edgepoints[0].x = -32768;
769     edgepoints[0].y = 32768;
770  
771     edgepoints[1].x = 32768;
772     edgepoints[1].y = 32768;
773  
774     edgepoints[2].x = 32768;
775     edgepoints[2].y = -32768;
776  
777     edgepoints[3].x = -32768;
778     edgepoints[3].y = -32768;
779  
780     //printf( "carving (with %d clippers):\n",numclippers);
781  
782     // We'll now clip the polygon with each of the divlines. The left side of
783     // each divline is discarded.
784     //OGL_DrawEdges(numedgepoints,edgepoints,numclippers,clippers,-1);
785     for(i=0; i<numclippers; i++)
786     {
787         fdivline_t *curclip = clippers+i;
788  
789         //OGL_DrawEdges(numedgepoints,edgepoints,numclippers,clippers,i);
790         // First we'll determine the side of each vertex. Points are allowed
791         // to be on the line.
792         for(k=0; k<numedgepoints; k++)
793         {
794             sidelist[k] = detSideFloat(edgepoints+k, curclip);
795             //printf( "%d: %d, ",k,sidelist[k]);
796         }
797         //printf("\n");
798
799         for(k=0; k<numedgepoints; k++)
800         {
801             int startIdx = k, endIdx = k+1;
802  
803             // Check the end index.
804             if(endIdx == numedgepoints) endIdx = 0; // Wrap-around.
805  
806             // Clipping will happen when the ends are on different sides.
807             if(sidelist[startIdx] != sidelist[endIdx])
808             {
809                 fvertex_t newvert;
810                 //printf( "  clipping %d - %d\n",startIdx,endIdx);
811                 // Find the intersection point of intersecting lines.
812                 findIntersectionVertex(edgepoints+startIdx, edgepoints+endIdx,
813                     curclip, &newvert);
814  
815                 // Add the new vertex. Also modify the sidelist.
816                 edgepoints =
817 (fvertex_t*)realloc(edgepoints,(++numedgepoints)*sizeof(fvertex_t));
818                 if(numedgepoints >= MAX_CC_SIDES) I_Error("Too many points in carver.\n");
819  
820                 // Make room for the new vertex.
821                 memmove(edgepoints+endIdx+1, edgepoints+endIdx,
822                     (numedgepoints-endIdx-1)*sizeof(fvertex_t));
823                 memcpy(edgepoints+endIdx, &newvert, sizeof(newvert));
824  
825                 memmove(sidelist+endIdx+1, sidelist+endIdx,
826 numedgepoints-endIdx-1);
827                 sidelist[endIdx] = 1;
828  
829                 // Skip over the new vertex.
830                 k++;
831             }
832         }
833  
834         // Now we must discard the points that are on the wrong side.
835         for(k=0; k<numedgepoints; k++)
836             if(!sidelist[k])
837             {
838                 memmove(edgepoints+k, edgepoints+k+1,
839 (numedgepoints-k-1)*sizeof(fvertex_t));
840                 memmove(sidelist+k, sidelist+k+1, numedgepoints-k-1);
841                 numedgepoints--;
842                 k--;
843             }
844  
845         //OGL_DrawEdges(numedgepoints,edgepoints,numclippers,clippers,i);
846     }
847
848     if(!numedgepoints)
849     {
850         //I_Error("All carved away!\n");
851         printf( "All carved away: subsector %p\n", ssec);
852         ssec->numedgeverts = 0;
853         ssec->edgeverts = 0;
854         ssec->origedgeverts = 0;
855     }
856     else
857     {
858         // Screen out consecutive identical points.
859         for(i=0; i<numedgepoints; i++)
860         {
861             int previdx = i-1;
862             if(previdx < 0) previdx = numedgepoints-1;
863             if(edgepoints[i].x == edgepoints[previdx].x
864                 && edgepoints[i].y == edgepoints[previdx].y)
865             {
866                 // This point (i) must be removed.
867                 memmove(edgepoints+i, edgepoints+i+1,
868 sizeof(fvertex_t)*(numedgepoints-i-1));
869                 numedgepoints--;
870                 i--;
871             }
872         }
873         // We need these with dynamic lights.
874         ssec->origedgeverts =
875 (fvertex_t*)Z_Malloc(sizeof(fvertex_t)*numedgepoints, PU_LEVEL, 0);
876         memcpy(ssec->origedgeverts, edgepoints,
877 sizeof(fvertex_t)*numedgepoints);
878  
879         // Find the center point. Do this by first finding the bounding box.
880         //cenx = edgepoints[0].x;
881         //ceny = edgepoints[0].y;
882         ssec->bbox[0].x = ssec->bbox[1].x = edgepoints[0].x;
883         ssec->bbox[0].y = ssec->bbox[1].y = edgepoints[0].y;
884         for(i=1; i<numedgepoints; i++)
885         {
886             //printf( "  %i: (%f, %f)\n", i, edgepoints[i].x,
887             //edgepoints[i].y);
888             //cenx += edgepoints[i].x;
889             //ceny += edgepoints[i].y;
890             if(edgepoints[i].x < ssec->bbox[0].x) ssec->bbox[0].x =
891 edgepoints[i].x;
892             if(edgepoints[i].y < ssec->bbox[0].y) ssec->bbox[0].y =
893 edgepoints[i].y;
894             if(edgepoints[i].x > ssec->bbox[1].x) ssec->bbox[1].x =
895 edgepoints[i].x;
896             if(edgepoints[i].y > ssec->bbox[1].y) ssec->bbox[1].y =
897 edgepoints[i].y;
898         }
899         //cenx /= numedgepoints;
900         //ceny /= numedgepoints;
901         ssec->midpoint.x = (ssec->bbox[1].x+ssec->bbox[0].x)/2;
902         ssec->midpoint.y = (ssec->bbox[1].y+ssec->bbox[0].y)/2;
903         //cenx = midpoint.x;
904         //ceny = midpoint.y;
905  
906         // Make slight adjustments to patch up those ugly, small gaps.
907         for(i=0; i<numedgepoints; i++)
908         {
909             float dx = edgepoints[i].x - ssec->midpoint.x,
910                 dy = edgepoints[i].y - ssec->midpoint.y;
911             float dlen = (float) sqrt(dx*dx + dy*dy) * 3;
912             if(dlen)
913             {
914                 edgepoints[i].x += dx/dlen;
915                 edgepoints[i].y += dy/dlen;
916             }
917         }
918  
919         ssec->numedgeverts = numedgepoints;
920         ssec->edgeverts =
921 (fvertex_t*)Z_Malloc(sizeof(fvertex_t)*numedgepoints,PU_LEVEL,0);
922         memcpy(ssec->edgeverts, edgepoints, sizeof(fvertex_t)*numedgepoints);
923     }
924  
925     // We're done, free the edgepoints memory.
926     free(clippers);
927     free(edgepoints);
928 }
929
930
931 void P_CreateFloorsAndCeilings( int bspnode, int numdivlines,
932                                 divline_t* divlines )
933 {
934     node_t      *nod;
935     divline_t   *childlist, *dl;
936     int         childlistsize = numdivlines+1;
937  
938     // If this is a subsector we are dealing with, begin carving with the
939     // given list.
940     if(bspnode & NF_SUBSECTOR)
941     {
942  
943         // We have arrived at a subsector. The divline list contains all
944         // the partition lines that carve out the subsector.
945  
946         //printf( "subsector %d: %d
947         //divlines\n",bspnode&(~NF_SUBSECTOR),numdivlines);
948  
949         int ssidx = bspnode & (~NF_SUBSECTOR);
950         //if(ssidx < 10)
951         P_ConvexCarver(subsectors+ssidx, numdivlines, divlines);
952  
953         //printf( "subsector %d: %d edgeverts\n", ssidx,
954         //subsectors[ssidx].numedgeverts);
955         // This leaf is done.
956         return;
957     }
958  
959     // Get a pointer to the node.
960     nod = nodes + bspnode;
961  
962     // Allocate a new list for each child.
963     childlist = (divline_t*)malloc(childlistsize*sizeof(divline_t));
964  
965     // Copy the previous lines.
966     if(divlines) memcpy(childlist,divlines,numdivlines*sizeof(divline_t));
967  
968     dl = childlist + numdivlines;
969     dl->x = nod->x;
970     dl->y = nod->y;
971     // The right child gets the original line (LEFT side clipped).
972     dl->dx = nod->dx;
973     dl->dy = nod->dy;
974     P_CreateFloorsAndCeilings(nod->children[0],childlistsize,childlist);
975
976     // The left side. We must reverse the line, otherwise the wrong
977     // side would get clipped.
978     dl->dx = -nod->dx;
979     dl->dy = -nod->dy;
980     P_CreateFloorsAndCeilings(nod->children[1],childlistsize,childlist);
981  
982     // We are finishing with this node, free the allocated list.
983     free(childlist);
984 }
985
986
987 void P_SkyFix()
988 {
989     int         i;
990  
991     // We need to check all the linedefs.
992     for(i=0; i<numlines; i++)
993     {
994         line_t *line = lines + i;
995         sector_t *front = line->frontsector, *back = line->backsector;
996         int fix = 0;
997         // The conditions!
998         if(!front || !back) continue;
999         // Both the front and back sectors must have the sky ceiling.
1000         if(front->ceilingpic != skyflatnum || back->ceilingpic != skyflatnum)
1001             continue;
1002         // Operate on the lower sector.
1003         /*ST_Message("Line %d (f:%d, b:%d).\n", i, front->ceilingheight >>
1004          * FRACBITS,
1005             back->ceilingheight >> FRACBITS);*/
1006         if(front->ceilingheight < back->ceilingheight)
1007         {
1008             fix = (back->ceilingheight-front->ceilingheight) >> FRACBITS;
1009             if(fix > front->skyfix) front->skyfix = fix;
1010         }
1011         else if(front->ceilingheight > back->ceilingheight)
1012         {
1013             fix = (front->ceilingheight-back->ceilingheight) >> FRACBITS;
1014             if(fix > back->skyfix) back->skyfix = fix;
1015         }
1016     }
1017 }
1018 #endif
1019
1020
1021 //=============================================================================
1022
1023
1024 /*
1025 =================
1026 =
1027 = P_SetupLevel
1028 =
1029 =================
1030 */
1031
1032         extern boolean i_CDMusic;
1033
1034 void P_SetupLevel(int episode, int map, int playermask, skill_t skill)
1035 {
1036         int i;
1037         int parm;
1038         char lumpname[9];
1039         char auxName[128];
1040         int lumpnum;
1041         mobj_t *mobj;
1042
1043         for(i = 0; i < MAXPLAYERS; i++)
1044         {
1045                 players[i].killcount = players[i].secretcount
1046                         = players[i].itemcount = 0;
1047         }
1048         players[consoleplayer].viewz = 1; // will be set by player think
1049
1050         if(i_CDMusic == false)
1051         {
1052                 S_StartSongName("chess", true); // Waiting-for-level-load song
1053         }
1054
1055         Z_FreeTags(PU_LEVEL, PU_PURGELEVEL-1);
1056     
1057 #ifdef RENDER3D
1058     OGL_ResetData();
1059 #endif
1060
1061         P_InitThinkers();
1062         leveltime = 0;
1063
1064         if(DevMaps)
1065         {
1066                 sprintf(auxName, "%sMAP%02d.WAD", DevMapsDir, map);
1067                 W_OpenAuxiliary(auxName);
1068         }
1069         sprintf(lumpname, "MAP%02d", map);
1070         lumpnum = W_GetNumForName(lumpname);
1071         //
1072         // Begin processing map lumps
1073         // Note: most of this ordering is important
1074         //
1075         P_LoadBlockMap(lumpnum+ML_BLOCKMAP);
1076         P_LoadVertexes(lumpnum+ML_VERTEXES);
1077         P_LoadSectors(lumpnum+ML_SECTORS);
1078         P_LoadSideDefs(lumpnum+ML_SIDEDEFS);
1079         P_LoadLineDefs(lumpnum+ML_LINEDEFS);
1080         P_LoadSubsectors(lumpnum+ML_SSECTORS);
1081         P_LoadNodes(lumpnum+ML_NODES);
1082         P_LoadSegs(lumpnum+ML_SEGS);
1083     
1084 #ifdef RENDER3D
1085     // We need to carve out the floor/ceiling polygons of each subsector.
1086     // Walk the tree to do this.
1087     //ST_Message( "Floor/ceiling creation: begin at %d, ", ticcount);
1088     P_CreateFloorsAndCeilings(numnodes-1, 0, 0);
1089     // Also check if the sky needs a fix.
1090     P_SkyFix();
1091 #endif
1092
1093         rejectmatrix = W_CacheLumpNum(lumpnum+ML_REJECT, PU_LEVEL);
1094         P_GroupLines();
1095         bodyqueslot = 0;
1096         po_NumPolyobjs = 0;
1097         deathmatch_p = deathmatchstarts;
1098         P_LoadThings(lumpnum+ML_THINGS);
1099         PO_Init(lumpnum+ML_THINGS); // Initialize the polyobjs
1100         P_LoadACScripts(lumpnum+ML_BEHAVIOR); // ACS object code
1101         //
1102         // End of map lump processing
1103         //
1104         if(DevMaps)
1105         {
1106                 // Close the auxiliary file, but don't free its loaded lumps.
1107                 // The next call to W_OpenAuxiliary() will do a full shutdown
1108                 // of the current auxiliary WAD (free lumps and info lists).
1109                 W_CloseAuxiliaryFile();
1110                 W_UsePrimary();
1111         }
1112
1113         // If deathmatch, randomly spawn the active players
1114         TimerGame = 0;
1115         if(deathmatch)
1116         {
1117                 for (i=0 ; i<MAXPLAYERS ; i++)
1118                 {
1119                         if (playeringame[i])
1120                         {   // must give a player spot before deathmatchspawn
1121                                 mobj = P_SpawnMobj (playerstarts[0][i].x<<16,
1122                                         playerstarts[0][i].y<<16,0, MT_PLAYER_FIGHTER);
1123                                 players[i].mo = mobj;
1124                                 G_DeathMatchSpawnPlayer (i);
1125                                 P_RemoveMobj (mobj);
1126                         }
1127                 }
1128                 parm = M_CheckParm("-timer");
1129                 if(parm && parm < myargc-1)
1130                 {
1131                         TimerGame = atoi(myargv[parm+1])*35*60;
1132                 }
1133         }
1134
1135 // set up world state
1136         P_SpawnSpecials ();
1137
1138 // build subsector connect matrix
1139 //      P_ConnectSubsectors ();
1140
1141 // Load colormap and set the fullbright flag
1142         i = P_GetMapFadeTable(gamemap);
1143         W_ReadLump(i, colormaps);
1144         if(i == W_GetNumForName("COLORMAP"))
1145         {
1146                 LevelUseFullBright = true;
1147 #ifdef RENDER3D
1148         OGL_UseWhiteFog(false);
1149 #endif
1150         }
1151         else
1152         { // Probably fog ... don't use fullbright sprites
1153                 LevelUseFullBright = false;
1154 #ifdef RENDER3D
1155         if(i == W_GetNumForName("FOGMAP"))
1156         {
1157             // Tell the renderer to turn on the fog.
1158             OGL_UseWhiteFog(true);
1159         }
1160 #endif
1161         }
1162
1163 // preload graphics
1164         if (precache)
1165                 R_PrecacheLevel ();
1166
1167         // Check if the level is a lightning level
1168         P_InitLightning();
1169
1170         S_StopAllSound();
1171         SN_StopAllSequences();
1172         S_StartSong(gamemap, true);
1173
1174 //printf ("free memory: 0x%x\n", Z_FreeMemory());
1175
1176 }
1177
1178 //==========================================================================
1179 //
1180 // InitMapInfo
1181 //
1182 //==========================================================================
1183
1184 static void InitMapInfo(void)
1185 {
1186         int map;
1187         int mapMax;
1188         int mcmdValue;
1189         mapInfo_t *info;
1190         char songMulch[10];
1191
1192         mapMax = 1;
1193
1194         // Put defaults into MapInfo[0]
1195         info = MapInfo;
1196         info->cluster = 0;
1197         info->warpTrans = 0;
1198         info->nextMap = 1; // Always go to map 1 if not specified
1199         info->cdTrack = 1;
1200         info->sky1Texture = R_TextureNumForName(DEFAULT_SKY_NAME);
1201         info->sky2Texture = info->sky1Texture;
1202         info->sky1ScrollDelta = 0;
1203         info->sky2ScrollDelta = 0;
1204         info->doubleSky = false;
1205         info->lightning = false;
1206         info->fadetable = W_GetNumForName(DEFAULT_FADE_TABLE);
1207         strcpy(info->name, UNKNOWN_MAP_NAME);
1208
1209 //      strcpy(info->songLump, DEFAULT_SONG_LUMP);
1210         SC_Open(MAPINFO_SCRIPT_NAME);
1211         while(SC_GetString())
1212         {
1213                 if(SC_Compare("MAP") == false)
1214                 {
1215                         SC_ScriptError(NULL);
1216                 }
1217                 SC_MustGetNumber();
1218                 if(sc_Number < 1 || sc_Number > 99)
1219                 { // 
1220                         SC_ScriptError(NULL);
1221                 }
1222                 map = sc_Number;
1223
1224                 info = &MapInfo[map];
1225
1226                 // Save song lump name
1227                 strcpy(songMulch, info->songLump);
1228
1229                 // Copy defaults to current map definition
1230                 memcpy(info, &MapInfo[0], sizeof(*info));
1231
1232                 // Restore song lump name
1233                 strcpy(info->songLump, songMulch);
1234
1235                 // The warp translation defaults to the map number
1236                 info->warpTrans = map;
1237
1238                 // Map name must follow the number
1239                 SC_MustGetString();
1240                 strcpy(info->name, sc_String);
1241
1242                 // Process optional tokens
1243                 while(SC_GetString())
1244                 {
1245                         if(SC_Compare("MAP"))
1246                         { // Start next map definition
1247                                 SC_UnGet();
1248                                 break;
1249                         }
1250                         mcmdValue = MapCmdIDs[SC_MustMatchString(MapCmdNames)];
1251                         switch(mcmdValue)
1252                         {
1253                                 case MCMD_CLUSTER:
1254                                         SC_MustGetNumber();
1255                                         info->cluster = sc_Number;
1256                                         break;
1257                                 case MCMD_WARPTRANS:
1258                                         SC_MustGetNumber();
1259                                         info->warpTrans = sc_Number;
1260                                         break;
1261                                 case MCMD_NEXT:
1262                                         SC_MustGetNumber();
1263                                         info->nextMap = sc_Number;
1264                                         break;
1265                                 case MCMD_CDTRACK:
1266                                         SC_MustGetNumber();
1267                                         info->cdTrack = sc_Number;
1268                                         break;
1269                                 case MCMD_SKY1:
1270                                         SC_MustGetString();
1271                                         info->sky1Texture = R_TextureNumForName(sc_String);
1272                                         SC_MustGetNumber();
1273                                         info->sky1ScrollDelta = sc_Number<<8;
1274                                         break;
1275                                 case MCMD_SKY2:
1276                                         SC_MustGetString();
1277                                         info->sky2Texture = R_TextureNumForName(sc_String);
1278                                         SC_MustGetNumber();
1279                                         info->sky2ScrollDelta = sc_Number<<8;
1280                                         break;
1281                                 case MCMD_DOUBLESKY:
1282                                         info->doubleSky = true;
1283                                         break;
1284                                 case MCMD_LIGHTNING:
1285                                         info->lightning = true;
1286                                         break;
1287                                 case MCMD_FADETABLE:
1288                                         SC_MustGetString();
1289                                         info->fadetable = W_GetNumForName(sc_String);
1290                                         break;
1291                                 case MCMD_CD_STARTTRACK:
1292                                 case MCMD_CD_END1TRACK:
1293                                 case MCMD_CD_END2TRACK:
1294                                 case MCMD_CD_END3TRACK:
1295                                 case MCMD_CD_INTERTRACK:
1296                                 case MCMD_CD_TITLETRACK:
1297                                         SC_MustGetNumber();
1298                                         cd_NonLevelTracks[mcmdValue-MCMD_CD_STARTTRACK] = 
1299                                                 sc_Number;
1300                                         break;
1301                         }
1302                 }
1303                 mapMax = map > mapMax ? map : mapMax;
1304         }
1305         SC_Close();
1306         MapCount = mapMax;
1307 }
1308
1309 //==========================================================================
1310 //
1311 // P_GetMapCluster
1312 //
1313 //==========================================================================
1314
1315 int P_GetMapCluster(int map)
1316 {
1317         return MapInfo[QualifyMap(map)].cluster;
1318 }
1319
1320 //==========================================================================
1321 //
1322 // P_GetMapCDTrack
1323 //
1324 //==========================================================================
1325
1326 int P_GetMapCDTrack(int map)
1327 {
1328         return MapInfo[QualifyMap(map)].cdTrack;
1329 }
1330
1331 //==========================================================================
1332 //
1333 // P_GetMapWarpTrans
1334 //
1335 //==========================================================================
1336
1337 int P_GetMapWarpTrans(int map)
1338 {
1339         return MapInfo[QualifyMap(map)].warpTrans;
1340 }
1341
1342 //==========================================================================
1343 //
1344 // P_GetMapNextMap
1345 //
1346 //==========================================================================
1347
1348 int P_GetMapNextMap(int map)
1349 {
1350         return MapInfo[QualifyMap(map)].nextMap;
1351 }
1352
1353 //==========================================================================
1354 //
1355 // P_TranslateMap
1356 //
1357 // Returns the actual map number given a warp map number.
1358 //
1359 //==========================================================================
1360
1361 int P_TranslateMap(int map)
1362 {
1363         int i;
1364
1365         for(i = 1; i < 99; i++) // Make this a macro
1366         {
1367                 if(MapInfo[i].warpTrans == map)
1368                 {
1369                         return i;
1370                 }
1371         }
1372         // Not found
1373         return -1;
1374 }
1375
1376 //==========================================================================
1377 //
1378 // P_GetMapSky1Texture
1379 //
1380 //==========================================================================
1381
1382 int P_GetMapSky1Texture(int map)
1383 {
1384         return MapInfo[QualifyMap(map)].sky1Texture;
1385 }
1386
1387 //==========================================================================
1388 //
1389 // P_GetMapSky2Texture
1390 //
1391 //==========================================================================
1392
1393 int P_GetMapSky2Texture(int map)
1394 {
1395         return MapInfo[QualifyMap(map)].sky2Texture;
1396 }
1397
1398 //==========================================================================
1399 //
1400 // P_GetMapName
1401 //
1402 //==========================================================================
1403
1404 char *P_GetMapName(int map)
1405 {
1406         return MapInfo[QualifyMap(map)].name;
1407 }
1408
1409 //==========================================================================
1410 //
1411 // P_GetMapSky1ScrollDelta
1412 //
1413 //==========================================================================
1414
1415 fixed_t P_GetMapSky1ScrollDelta(int map)
1416 {
1417         return MapInfo[QualifyMap(map)].sky1ScrollDelta;
1418 }
1419
1420 //==========================================================================
1421 //
1422 // P_GetMapSky2ScrollDelta
1423 //
1424 //==========================================================================
1425
1426 fixed_t P_GetMapSky2ScrollDelta(int map)
1427 {
1428         return MapInfo[QualifyMap(map)].sky2ScrollDelta;
1429 }
1430
1431 //==========================================================================
1432 //
1433 // P_GetMapDoubleSky
1434 //
1435 //==========================================================================
1436
1437 boolean P_GetMapDoubleSky(int map)
1438 {
1439         return MapInfo[QualifyMap(map)].doubleSky;
1440 }
1441
1442 //==========================================================================
1443 //
1444 // P_GetMapLightning
1445 //
1446 //==========================================================================
1447
1448 boolean P_GetMapLightning(int map)
1449 {
1450         return MapInfo[QualifyMap(map)].lightning;
1451 }
1452
1453 //==========================================================================
1454 //
1455 // P_GetMapFadeTable
1456 //
1457 //==========================================================================
1458
1459 boolean P_GetMapFadeTable(int map)
1460 {
1461         return MapInfo[QualifyMap(map)].fadetable;
1462 }
1463
1464 //==========================================================================
1465 //
1466 // P_GetMapSongLump
1467 //
1468 //==========================================================================
1469
1470 char *P_GetMapSongLump(int map)
1471 {
1472         if(!strcasecmp(MapInfo[QualifyMap(map)].songLump, DEFAULT_SONG_LUMP))
1473         {
1474                 return NULL;
1475         }
1476         else
1477         {
1478                 return MapInfo[QualifyMap(map)].songLump;
1479         }
1480 }
1481
1482 //==========================================================================
1483 //
1484 // P_PutMapSongLump
1485 //
1486 //==========================================================================
1487
1488 void P_PutMapSongLump(int map, char *lumpName)
1489 {
1490         if(map < 1 || map > MapCount)
1491         {
1492                 return;
1493         }
1494         strcpy(MapInfo[map].songLump, lumpName);
1495 }
1496
1497 //==========================================================================
1498 //
1499 // P_GetCDStartTrack
1500 //
1501 //==========================================================================
1502
1503 int P_GetCDStartTrack(void)
1504 {
1505         return cd_NonLevelTracks[MCMD_CD_STARTTRACK-MCMD_CD_STARTTRACK];
1506 }
1507
1508 //==========================================================================
1509 //
1510 // P_GetCDEnd1Track
1511 //
1512 //==========================================================================
1513
1514 int P_GetCDEnd1Track(void)
1515 {
1516         return cd_NonLevelTracks[MCMD_CD_END1TRACK-MCMD_CD_STARTTRACK];
1517 }
1518
1519 //==========================================================================
1520 //
1521 // P_GetCDEnd2Track
1522 //
1523 //==========================================================================
1524
1525 int P_GetCDEnd2Track(void)
1526 {
1527         return cd_NonLevelTracks[MCMD_CD_END2TRACK-MCMD_CD_STARTTRACK];
1528 }
1529
1530 //==========================================================================
1531 //
1532 // P_GetCDEnd3Track
1533 //
1534 //==========================================================================
1535
1536 int P_GetCDEnd3Track(void)
1537 {
1538         return cd_NonLevelTracks[MCMD_CD_END3TRACK-MCMD_CD_STARTTRACK];
1539 }
1540
1541 //==========================================================================
1542 //
1543 // P_GetCDIntermissionTrack
1544 //
1545 //==========================================================================
1546
1547 int P_GetCDIntermissionTrack(void)
1548 {
1549         return cd_NonLevelTracks[MCMD_CD_INTERTRACK-MCMD_CD_STARTTRACK];
1550 }
1551
1552 //==========================================================================
1553 //
1554 // P_GetCDTitleTrack
1555 //
1556 //==========================================================================
1557
1558 int P_GetCDTitleTrack(void)
1559 {
1560         return cd_NonLevelTracks[MCMD_CD_TITLETRACK-MCMD_CD_STARTTRACK];
1561 }
1562
1563 //==========================================================================
1564 //
1565 // QualifyMap
1566 //
1567 //==========================================================================
1568
1569 static int QualifyMap(int map)
1570 {
1571         return (map < 1 || map > MapCount) ? 0 : map;
1572 }
1573
1574 //==========================================================================
1575 //
1576 // P_Init
1577 //
1578 //==========================================================================
1579
1580 void P_Init(void)
1581 {
1582         InitMapInfo();
1583         P_InitSwitchList();
1584         P_InitFTAnims(); // Init flat and texture animations
1585         P_InitTerrainTypes();
1586         P_InitLava();
1587         R_InitSprites(sprnames);
1588 }
1589
1590
1591 // Special early initializer needed to start sound before R_Init()
1592 void InitMapMusicInfo(void)
1593 {
1594         int i;
1595
1596         for (i=0; i<99; i++)
1597         {
1598                 strcpy(MapInfo[i].songLump, DEFAULT_SONG_LUMP);
1599         }
1600         MapCount = 98;
1601 }
1602
1603 /*
1604 void My_Debug(void)
1605 {
1606         int i;
1607
1608         printf("My debug stuff ----------------------\n");
1609         printf("gamemap=%d\n",gamemap);
1610         for (i=0; i<10; i++)
1611         {
1612                 printf("i=%d  songlump=%s\n",i,MapInfo[i].songLump);
1613         }
1614 }
1615 */
1616