]> icculus.org git repositories - theoddone33/hhexen.git/blob - base/p_setup.c
Initial revision
[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 =
732 (fdivline_t*)_alloca(numclippers*sizeof(fdivline_t));
733     int         i, k, numedgepoints;
734     fvertex_t   *edgepoints;
735     unsigned char sidelist[MAX_CC_SIDES];
736 #ifndef RENDER3D
737     float       cenx, ceny;
738 #endif
739  
740     // Convert the divlines to float, in reverse order.
741     //printf( "%d clippers (%d pls, %d
742     //segs):\n",numclippers,num,ssec->numlines);
743     for(i=0; i<numclippers; i++)
744     {
745         if(i<num)
746         {
747             clippers[i].x = FIX2FLT(list[num-i-1].x);
748             clippers[i].y = FIX2FLT(list[num-i-1].y);
749             clippers[i].dx = FIX2FLT(list[num-i-1].dx);
750             clippers[i].dy = FIX2FLT(list[num-i-1].dy);
751         }
752         else
753         {
754             seg_t *seg = segs+(ssec->firstline+i-num);
755             clippers[i].x = FIX2FLT(seg->v1->x);
756             clippers[i].y = FIX2FLT(seg->v1->y);
757             clippers[i].dx = FIX2FLT(seg->v2->x - seg->v1->x);
758             clippers[i].dy = FIX2FLT(seg->v2->y - seg->v1->y);
759         }
760         //printf( "  %d: x=%f y=%f dx=%f
761         //dy=%f\n",i,clippers[i].x,clippers[i].y,clippers[i].dx,clippers[i].dy);
762     }
763     //printf( "\n");
764
765     // Setup the 'worldwide' polygon.
766     numedgepoints = 4;
767     edgepoints = (fvertex_t*)malloc(numedgepoints*sizeof(fvertex_t));
768  
769     edgepoints[0].x = -32768;
770     edgepoints[0].y = 32768;
771  
772     edgepoints[1].x = 32768;
773     edgepoints[1].y = 32768;
774  
775     edgepoints[2].x = 32768;
776     edgepoints[2].y = -32768;
777  
778     edgepoints[3].x = -32768;
779     edgepoints[3].y = -32768;
780  
781     //printf( "carving (with %d clippers):\n",numclippers);
782  
783     // We'll now clip the polygon with each of the divlines. The left side of
784     // each divline is discarded.
785     //OGL_DrawEdges(numedgepoints,edgepoints,numclippers,clippers,-1);
786     for(i=0; i<numclippers; i++)
787     {
788         fdivline_t *curclip = clippers+i;
789  
790         //OGL_DrawEdges(numedgepoints,edgepoints,numclippers,clippers,i);
791         // First we'll determine the side of each vertex. Points are allowed
792         // to be on the line.
793         for(k=0; k<numedgepoints; k++)
794         {
795             sidelist[k] = detSideFloat(edgepoints+k, curclip);
796             //printf( "%d: %d, ",k,sidelist[k]);
797         }
798         //printf("\n");
799
800         for(k=0; k<numedgepoints; k++)
801         {
802             int startIdx = k, endIdx = k+1;
803  
804             // Check the end index.
805             if(endIdx == numedgepoints) endIdx = 0; // Wrap-around.
806  
807             // Clipping will happen when the ends are on different sides.
808             if(sidelist[startIdx] != sidelist[endIdx])
809             {
810                 fvertex_t newvert;
811                 //printf( "  clipping %d - %d\n",startIdx,endIdx);
812                 // Find the intersection point of intersecting lines.
813                 findIntersectionVertex(edgepoints+startIdx, edgepoints+endIdx,
814                     curclip, &newvert);
815  
816                 // Add the new vertex. Also modify the sidelist.
817                 edgepoints =
818 (fvertex_t*)realloc(edgepoints,(++numedgepoints)*sizeof(fvertex_t));
819                 if(numedgepoints >= MAX_CC_SIDES) I_Error("Too many points in
820 carver.\n");
821  
822                 // Make room for the new vertex.
823                 memmove(edgepoints+endIdx+1, edgepoints+endIdx,
824                     (numedgepoints-endIdx-1)*sizeof(fvertex_t));
825                 memcpy(edgepoints+endIdx, &newvert, sizeof(newvert));
826  
827                 memmove(sidelist+endIdx+1, sidelist+endIdx,
828 numedgepoints-endIdx-1);
829                 sidelist[endIdx] = 1;
830  
831                 // Skip over the new vertex.
832                 k++;
833             }
834         }
835  
836         // Now we must discard the points that are on the wrong side.
837         for(k=0; k<numedgepoints; k++)
838             if(!sidelist[k])
839             {
840                 memmove(edgepoints+k, edgepoints+k+1,
841 (numedgepoints-k-1)*sizeof(fvertex_t));
842                 memmove(sidelist+k, sidelist+k+1, numedgepoints-k-1);
843                 numedgepoints--;
844                 k--;
845             }
846  
847         //OGL_DrawEdges(numedgepoints,edgepoints,numclippers,clippers,i);
848     }
849
850     if(!numedgepoints)
851     {
852         //I_Error("All carved away!\n");
853         printf( "All carved away: subsector %p\n", ssec);
854         ssec->numedgeverts = 0;
855         ssec->edgeverts = 0;
856         ssec->origedgeverts = 0;
857     }
858     else
859     {
860         // Screen out consecutive identical points.
861         for(i=0; i<numedgepoints; i++)
862         {
863             int previdx = i-1;
864             if(previdx < 0) previdx = numedgepoints-1;
865             if(edgepoints[i].x == edgepoints[previdx].x
866                 && edgepoints[i].y == edgepoints[previdx].y)
867             {
868                 // This point (i) must be removed.
869                 memmove(edgepoints+i, edgepoints+i+1,
870 sizeof(fvertex_t)*(numedgepoints-i-1));
871                 numedgepoints--;
872                 i--;
873             }
874         }
875         // We need these with dynamic lights.
876         ssec->origedgeverts =
877 (fvertex_t*)Z_Malloc(sizeof(fvertex_t)*numedgepoints, PU_LEVEL, 0);
878         memcpy(ssec->origedgeverts, edgepoints,
879 sizeof(fvertex_t)*numedgepoints);
880  
881         // Find the center point. Do this by first finding the bounding box.
882         //cenx = edgepoints[0].x;
883         //ceny = edgepoints[0].y;
884         ssec->bbox[0].x = ssec->bbox[1].x = edgepoints[0].x;
885         ssec->bbox[0].y = ssec->bbox[1].y = edgepoints[0].y;
886         for(i=1; i<numedgepoints; i++)
887         {
888             //printf( "  %i: (%f, %f)\n", i, edgepoints[i].x,
889             //edgepoints[i].y);
890             //cenx += edgepoints[i].x;
891             //ceny += edgepoints[i].y;
892             if(edgepoints[i].x < ssec->bbox[0].x) ssec->bbox[0].x =
893 edgepoints[i].x;
894             if(edgepoints[i].y < ssec->bbox[0].y) ssec->bbox[0].y =
895 edgepoints[i].y;
896             if(edgepoints[i].x > ssec->bbox[1].x) ssec->bbox[1].x =
897 edgepoints[i].x;
898             if(edgepoints[i].y > ssec->bbox[1].y) ssec->bbox[1].y =
899 edgepoints[i].y;
900         }
901         //cenx /= numedgepoints;
902         //ceny /= numedgepoints;
903         ssec->midpoint.x = (ssec->bbox[1].x+ssec->bbox[0].x)/2;
904         ssec->midpoint.y = (ssec->bbox[1].y+ssec->bbox[0].y)/2;
905         //cenx = midpoint.x;
906         //ceny = midpoint.y;
907  
908         // Make slight adjustments to patch up those ugly, small gaps.
909         for(i=0; i<numedgepoints; i++)
910         {
911             float dx = edgepoints[i].x - ssec->midpoint.x,
912                 dy = edgepoints[i].y - ssec->midpoint.y;
913             float dlen = (float) sqrt(dx*dx + dy*dy) * 3;
914             if(dlen)
915             {
916                 edgepoints[i].x += dx/dlen;
917                 edgepoints[i].y += dy/dlen;
918             }
919         }
920  
921         ssec->numedgeverts = numedgepoints;
922         ssec->edgeverts =
923 (fvertex_t*)Z_Malloc(sizeof(fvertex_t)*numedgepoints,PU_LEVEL,0);
924         memcpy(ssec->edgeverts, edgepoints, sizeof(fvertex_t)*numedgepoints);
925     }
926  
927     // We're done, free the edgepoints memory.
928     free(edgepoints);
929 }
930
931
932 void P_CreateFloorsAndCeilings( int bspnode, int numdivlines,
933                                 divline_t* divlines )
934 {
935     node_t      *nod;
936     divline_t   *childlist, *dl;
937     int         childlistsize = numdivlines+1;
938  
939     // If this is a subsector we are dealing with, begin carving with the
940     // given list.
941     if(bspnode & NF_SUBSECTOR)
942     {
943  
944         // We have arrived at a subsector. The divline list contains all
945         // the partition lines that carve out the subsector.
946  
947         //printf( "subsector %d: %d
948         //divlines\n",bspnode&(~NF_SUBSECTOR),numdivlines);
949  
950         int ssidx = bspnode & (~NF_SUBSECTOR);
951         //if(ssidx < 10)
952         P_ConvexCarver(subsectors+ssidx, numdivlines, divlines);
953  
954         //printf( "subsector %d: %d edgeverts\n", ssidx,
955         //subsectors[ssidx].numedgeverts);
956         // This leaf is done.
957         return;
958     }
959  
960     // Get a pointer to the node.
961     nod = nodes + bspnode;
962  
963     // Allocate a new list for each child.
964     childlist = (divline_t*)malloc(childlistsize*sizeof(divline_t));
965  
966     // Copy the previous lines.
967     if(divlines) memcpy(childlist,divlines,numdivlines*sizeof(divline_t));
968  
969     dl = childlist + numdivlines;
970     dl->x = nod->x;
971     dl->y = nod->y;
972     // The right child gets the original line (LEFT side clipped).
973     dl->dx = nod->dx;
974     dl->dy = nod->dy;
975     P_CreateFloorsAndCeilings(nod->children[0],childlistsize,childlist);
976
977     // The left side. We must reverse the line, otherwise the wrong
978     // side would get clipped.
979     dl->dx = -nod->dx;
980     dl->dy = -nod->dy;
981     P_CreateFloorsAndCeilings(nod->children[1],childlistsize,childlist);
982  
983     // We are finishing with this node, free the allocated list.
984     free(childlist);
985 }
986
987
988 void P_SkyFix()
989 {
990     int         i;
991  
992     // We need to check all the linedefs.
993     for(i=0; i<numlines; i++)
994     {
995         line_t *line = lines + i;
996         sector_t *front = line->frontsector, *back = line->backsector;
997         int fix = 0;
998         // The conditions!
999         if(!front || !back) continue;
1000         // Both the front and back sectors must have the sky ceiling.
1001         if(front->ceilingpic != skyflatnum || back->ceilingpic != skyflatnum)
1002             continue;
1003         // Operate on the lower sector.
1004         /*ST_Message("Line %d (f:%d, b:%d).\n", i, front->ceilingheight >>
1005          * FRACBITS,
1006             back->ceilingheight >> FRACBITS);*/
1007         if(front->ceilingheight < back->ceilingheight)
1008         {
1009             fix = (back->ceilingheight-front->ceilingheight) >> FRACBITS;
1010             if(fix > front->skyfix) front->skyfix = fix;
1011         }
1012         else if(front->ceilingheight > back->ceilingheight)
1013         {
1014             fix = (front->ceilingheight-back->ceilingheight) >> FRACBITS;
1015             if(fix > back->skyfix) back->skyfix = fix;
1016         }
1017     }
1018 }
1019 #endif
1020
1021
1022 //=============================================================================
1023
1024
1025 /*
1026 =================
1027 =
1028 = P_SetupLevel
1029 =
1030 =================
1031 */
1032
1033         extern boolean i_CDMusic;
1034
1035 void P_SetupLevel(int episode, int map, int playermask, skill_t skill)
1036 {
1037         int i;
1038         int parm;
1039         char lumpname[9];
1040         char auxName[128];
1041         int lumpnum;
1042         mobj_t *mobj;
1043
1044         for(i = 0; i < MAXPLAYERS; i++)
1045         {
1046                 players[i].killcount = players[i].secretcount
1047                         = players[i].itemcount = 0;
1048         }
1049         players[consoleplayer].viewz = 1; // will be set by player think
1050
1051         if(i_CDMusic == false)
1052         {
1053                 S_StartSongName("chess", true); // Waiting-for-level-load song
1054         }
1055
1056         Z_FreeTags(PU_LEVEL, PU_PURGELEVEL-1);
1057     
1058 #ifdef RENDER3D
1059     OGL_ResetData();
1060 #endif
1061
1062         P_InitThinkers();
1063         leveltime = 0;
1064
1065         if(DevMaps)
1066         {
1067                 sprintf(auxName, "%sMAP%02d.WAD", DevMapsDir, map);
1068                 W_OpenAuxiliary(auxName);
1069         }
1070         sprintf(lumpname, "MAP%02d", map);
1071         lumpnum = W_GetNumForName(lumpname);
1072         //
1073         // Begin processing map lumps
1074         // Note: most of this ordering is important
1075         //
1076         P_LoadBlockMap(lumpnum+ML_BLOCKMAP);
1077         P_LoadVertexes(lumpnum+ML_VERTEXES);
1078         P_LoadSectors(lumpnum+ML_SECTORS);
1079         P_LoadSideDefs(lumpnum+ML_SIDEDEFS);
1080         P_LoadLineDefs(lumpnum+ML_LINEDEFS);
1081         P_LoadSubsectors(lumpnum+ML_SSECTORS);
1082         P_LoadNodes(lumpnum+ML_NODES);
1083         P_LoadSegs(lumpnum+ML_SEGS);
1084     
1085 #ifdef RENDER3D
1086     // We need to carve out the floor/ceiling polygons of each subsector.
1087     // Walk the tree to do this.
1088     //ST_Message( "Floor/ceiling creation: begin at %d, ", ticcount);
1089     P_CreateFloorsAndCeilings(numnodes-1, 0, 0);
1090     // Also check if the sky needs a fix.
1091     P_SkyFix();
1092 #endif
1093
1094         rejectmatrix = W_CacheLumpNum(lumpnum+ML_REJECT, PU_LEVEL);
1095         P_GroupLines();
1096         bodyqueslot = 0;
1097         po_NumPolyobjs = 0;
1098         deathmatch_p = deathmatchstarts;
1099         P_LoadThings(lumpnum+ML_THINGS);
1100         PO_Init(lumpnum+ML_THINGS); // Initialize the polyobjs
1101         P_LoadACScripts(lumpnum+ML_BEHAVIOR); // ACS object code
1102         //
1103         // End of map lump processing
1104         //
1105         if(DevMaps)
1106         {
1107                 // Close the auxiliary file, but don't free its loaded lumps.
1108                 // The next call to W_OpenAuxiliary() will do a full shutdown
1109                 // of the current auxiliary WAD (free lumps and info lists).
1110                 W_CloseAuxiliaryFile();
1111                 W_UsePrimary();
1112         }
1113
1114         // If deathmatch, randomly spawn the active players
1115         TimerGame = 0;
1116         if(deathmatch)
1117         {
1118                 for (i=0 ; i<MAXPLAYERS ; i++)
1119                 {
1120                         if (playeringame[i])
1121                         {   // must give a player spot before deathmatchspawn
1122                                 mobj = P_SpawnMobj (playerstarts[0][i].x<<16,
1123                                         playerstarts[0][i].y<<16,0, MT_PLAYER_FIGHTER);
1124                                 players[i].mo = mobj;
1125                                 G_DeathMatchSpawnPlayer (i);
1126                                 P_RemoveMobj (mobj);
1127                         }
1128                 }
1129                 parm = M_CheckParm("-timer");
1130                 if(parm && parm < myargc-1)
1131                 {
1132                         TimerGame = atoi(myargv[parm+1])*35*60;
1133                 }
1134         }
1135
1136 // set up world state
1137         P_SpawnSpecials ();
1138
1139 // build subsector connect matrix
1140 //      P_ConnectSubsectors ();
1141
1142 // Load colormap and set the fullbright flag
1143         i = P_GetMapFadeTable(gamemap);
1144         W_ReadLump(i, colormaps);
1145         if(i == W_GetNumForName("COLORMAP"))
1146         {
1147                 LevelUseFullBright = true;
1148 #ifdef RENDER3D
1149         OGL_UseWhiteFog(false);
1150 #endif
1151         }
1152         else
1153         { // Probably fog ... don't use fullbright sprites
1154                 LevelUseFullBright = false;
1155 #ifdef RENDER3D
1156         if(i == W_GetNumForName("FOGMAP"))
1157         {
1158             // Tell the renderer to turn on the fog.
1159             OGL_UseWhiteFog(true);
1160         }
1161 #endif
1162         }
1163
1164 // preload graphics
1165         if (precache)
1166                 R_PrecacheLevel ();
1167
1168         // Check if the level is a lightning level
1169         P_InitLightning();
1170
1171         S_StopAllSound();
1172         SN_StopAllSequences();
1173         S_StartSong(gamemap, true);
1174
1175 //printf ("free memory: 0x%x\n", Z_FreeMemory());
1176
1177 }
1178
1179 //==========================================================================
1180 //
1181 // InitMapInfo
1182 //
1183 //==========================================================================
1184
1185 static void InitMapInfo(void)
1186 {
1187         int map;
1188         int mapMax;
1189         int mcmdValue;
1190         mapInfo_t *info;
1191         char songMulch[10];
1192
1193         mapMax = 1;
1194
1195         // Put defaults into MapInfo[0]
1196         info = MapInfo;
1197         info->cluster = 0;
1198         info->warpTrans = 0;
1199         info->nextMap = 1; // Always go to map 1 if not specified
1200         info->cdTrack = 1;
1201         info->sky1Texture = R_TextureNumForName(DEFAULT_SKY_NAME);
1202         info->sky2Texture = info->sky1Texture;
1203         info->sky1ScrollDelta = 0;
1204         info->sky2ScrollDelta = 0;
1205         info->doubleSky = false;
1206         info->lightning = false;
1207         info->fadetable = W_GetNumForName(DEFAULT_FADE_TABLE);
1208         strcpy(info->name, UNKNOWN_MAP_NAME);
1209
1210 //      strcpy(info->songLump, DEFAULT_SONG_LUMP);
1211         SC_Open(MAPINFO_SCRIPT_NAME);
1212         while(SC_GetString())
1213         {
1214                 if(SC_Compare("MAP") == false)
1215                 {
1216                         SC_ScriptError(NULL);
1217                 }
1218                 SC_MustGetNumber();
1219                 if(sc_Number < 1 || sc_Number > 99)
1220                 { // 
1221                         SC_ScriptError(NULL);
1222                 }
1223                 map = sc_Number;
1224
1225                 info = &MapInfo[map];
1226
1227                 // Save song lump name
1228                 strcpy(songMulch, info->songLump);
1229
1230                 // Copy defaults to current map definition
1231                 memcpy(info, &MapInfo[0], sizeof(*info));
1232
1233                 // Restore song lump name
1234                 strcpy(info->songLump, songMulch);
1235
1236                 // The warp translation defaults to the map number
1237                 info->warpTrans = map;
1238
1239                 // Map name must follow the number
1240                 SC_MustGetString();
1241                 strcpy(info->name, sc_String);
1242
1243                 // Process optional tokens
1244                 while(SC_GetString())
1245                 {
1246                         if(SC_Compare("MAP"))
1247                         { // Start next map definition
1248                                 SC_UnGet();
1249                                 break;
1250                         }
1251                         mcmdValue = MapCmdIDs[SC_MustMatchString(MapCmdNames)];
1252                         switch(mcmdValue)
1253                         {
1254                                 case MCMD_CLUSTER:
1255                                         SC_MustGetNumber();
1256                                         info->cluster = sc_Number;
1257                                         break;
1258                                 case MCMD_WARPTRANS:
1259                                         SC_MustGetNumber();
1260                                         info->warpTrans = sc_Number;
1261                                         break;
1262                                 case MCMD_NEXT:
1263                                         SC_MustGetNumber();
1264                                         info->nextMap = sc_Number;
1265                                         break;
1266                                 case MCMD_CDTRACK:
1267                                         SC_MustGetNumber();
1268                                         info->cdTrack = sc_Number;
1269                                         break;
1270                                 case MCMD_SKY1:
1271                                         SC_MustGetString();
1272                                         info->sky1Texture = R_TextureNumForName(sc_String);
1273                                         SC_MustGetNumber();
1274                                         info->sky1ScrollDelta = sc_Number<<8;
1275                                         break;
1276                                 case MCMD_SKY2:
1277                                         SC_MustGetString();
1278                                         info->sky2Texture = R_TextureNumForName(sc_String);
1279                                         SC_MustGetNumber();
1280                                         info->sky2ScrollDelta = sc_Number<<8;
1281                                         break;
1282                                 case MCMD_DOUBLESKY:
1283                                         info->doubleSky = true;
1284                                         break;
1285                                 case MCMD_LIGHTNING:
1286                                         info->lightning = true;
1287                                         break;
1288                                 case MCMD_FADETABLE:
1289                                         SC_MustGetString();
1290                                         info->fadetable = W_GetNumForName(sc_String);
1291                                         break;
1292                                 case MCMD_CD_STARTTRACK:
1293                                 case MCMD_CD_END1TRACK:
1294                                 case MCMD_CD_END2TRACK:
1295                                 case MCMD_CD_END3TRACK:
1296                                 case MCMD_CD_INTERTRACK:
1297                                 case MCMD_CD_TITLETRACK:
1298                                         SC_MustGetNumber();
1299                                         cd_NonLevelTracks[mcmdValue-MCMD_CD_STARTTRACK] = 
1300                                                 sc_Number;
1301                                         break;
1302                         }
1303                 }
1304                 mapMax = map > mapMax ? map : mapMax;
1305         }
1306         SC_Close();
1307         MapCount = mapMax;
1308 }
1309
1310 //==========================================================================
1311 //
1312 // P_GetMapCluster
1313 //
1314 //==========================================================================
1315
1316 int P_GetMapCluster(int map)
1317 {
1318         return MapInfo[QualifyMap(map)].cluster;
1319 }
1320
1321 //==========================================================================
1322 //
1323 // P_GetMapCDTrack
1324 //
1325 //==========================================================================
1326
1327 int P_GetMapCDTrack(int map)
1328 {
1329         return MapInfo[QualifyMap(map)].cdTrack;
1330 }
1331
1332 //==========================================================================
1333 //
1334 // P_GetMapWarpTrans
1335 //
1336 //==========================================================================
1337
1338 int P_GetMapWarpTrans(int map)
1339 {
1340         return MapInfo[QualifyMap(map)].warpTrans;
1341 }
1342
1343 //==========================================================================
1344 //
1345 // P_GetMapNextMap
1346 //
1347 //==========================================================================
1348
1349 int P_GetMapNextMap(int map)
1350 {
1351         return MapInfo[QualifyMap(map)].nextMap;
1352 }
1353
1354 //==========================================================================
1355 //
1356 // P_TranslateMap
1357 //
1358 // Returns the actual map number given a warp map number.
1359 //
1360 //==========================================================================
1361
1362 int P_TranslateMap(int map)
1363 {
1364         int i;
1365
1366         for(i = 1; i < 99; i++) // Make this a macro
1367         {
1368                 if(MapInfo[i].warpTrans == map)
1369                 {
1370                         return i;
1371                 }
1372         }
1373         // Not found
1374         return -1;
1375 }
1376
1377 //==========================================================================
1378 //
1379 // P_GetMapSky1Texture
1380 //
1381 //==========================================================================
1382
1383 int P_GetMapSky1Texture(int map)
1384 {
1385         return MapInfo[QualifyMap(map)].sky1Texture;
1386 }
1387
1388 //==========================================================================
1389 //
1390 // P_GetMapSky2Texture
1391 //
1392 //==========================================================================
1393
1394 int P_GetMapSky2Texture(int map)
1395 {
1396         return MapInfo[QualifyMap(map)].sky2Texture;
1397 }
1398
1399 //==========================================================================
1400 //
1401 // P_GetMapName
1402 //
1403 //==========================================================================
1404
1405 char *P_GetMapName(int map)
1406 {
1407         return MapInfo[QualifyMap(map)].name;
1408 }
1409
1410 //==========================================================================
1411 //
1412 // P_GetMapSky1ScrollDelta
1413 //
1414 //==========================================================================
1415
1416 fixed_t P_GetMapSky1ScrollDelta(int map)
1417 {
1418         return MapInfo[QualifyMap(map)].sky1ScrollDelta;
1419 }
1420
1421 //==========================================================================
1422 //
1423 // P_GetMapSky2ScrollDelta
1424 //
1425 //==========================================================================
1426
1427 fixed_t P_GetMapSky2ScrollDelta(int map)
1428 {
1429         return MapInfo[QualifyMap(map)].sky2ScrollDelta;
1430 }
1431
1432 //==========================================================================
1433 //
1434 // P_GetMapDoubleSky
1435 //
1436 //==========================================================================
1437
1438 boolean P_GetMapDoubleSky(int map)
1439 {
1440         return MapInfo[QualifyMap(map)].doubleSky;
1441 }
1442
1443 //==========================================================================
1444 //
1445 // P_GetMapLightning
1446 //
1447 //==========================================================================
1448
1449 boolean P_GetMapLightning(int map)
1450 {
1451         return MapInfo[QualifyMap(map)].lightning;
1452 }
1453
1454 //==========================================================================
1455 //
1456 // P_GetMapFadeTable
1457 //
1458 //==========================================================================
1459
1460 boolean P_GetMapFadeTable(int map)
1461 {
1462         return MapInfo[QualifyMap(map)].fadetable;
1463 }
1464
1465 //==========================================================================
1466 //
1467 // P_GetMapSongLump
1468 //
1469 //==========================================================================
1470
1471 char *P_GetMapSongLump(int map)
1472 {
1473         if(!strcasecmp(MapInfo[QualifyMap(map)].songLump, DEFAULT_SONG_LUMP))
1474         {
1475                 return NULL;
1476         }
1477         else
1478         {
1479                 return MapInfo[QualifyMap(map)].songLump;
1480         }
1481 }
1482
1483 //==========================================================================
1484 //
1485 // P_PutMapSongLump
1486 //
1487 //==========================================================================
1488
1489 void P_PutMapSongLump(int map, char *lumpName)
1490 {
1491         if(map < 1 || map > MapCount)
1492         {
1493                 return;
1494         }
1495         strcpy(MapInfo[map].songLump, lumpName);
1496 }
1497
1498 //==========================================================================
1499 //
1500 // P_GetCDStartTrack
1501 //
1502 //==========================================================================
1503
1504 int P_GetCDStartTrack(void)
1505 {
1506         return cd_NonLevelTracks[MCMD_CD_STARTTRACK-MCMD_CD_STARTTRACK];
1507 }
1508
1509 //==========================================================================
1510 //
1511 // P_GetCDEnd1Track
1512 //
1513 //==========================================================================
1514
1515 int P_GetCDEnd1Track(void)
1516 {
1517         return cd_NonLevelTracks[MCMD_CD_END1TRACK-MCMD_CD_STARTTRACK];
1518 }
1519
1520 //==========================================================================
1521 //
1522 // P_GetCDEnd2Track
1523 //
1524 //==========================================================================
1525
1526 int P_GetCDEnd2Track(void)
1527 {
1528         return cd_NonLevelTracks[MCMD_CD_END2TRACK-MCMD_CD_STARTTRACK];
1529 }
1530
1531 //==========================================================================
1532 //
1533 // P_GetCDEnd3Track
1534 //
1535 //==========================================================================
1536
1537 int P_GetCDEnd3Track(void)
1538 {
1539         return cd_NonLevelTracks[MCMD_CD_END3TRACK-MCMD_CD_STARTTRACK];
1540 }
1541
1542 //==========================================================================
1543 //
1544 // P_GetCDIntermissionTrack
1545 //
1546 //==========================================================================
1547
1548 int P_GetCDIntermissionTrack(void)
1549 {
1550         return cd_NonLevelTracks[MCMD_CD_INTERTRACK-MCMD_CD_STARTTRACK];
1551 }
1552
1553 //==========================================================================
1554 //
1555 // P_GetCDTitleTrack
1556 //
1557 //==========================================================================
1558
1559 int P_GetCDTitleTrack(void)
1560 {
1561         return cd_NonLevelTracks[MCMD_CD_TITLETRACK-MCMD_CD_STARTTRACK];
1562 }
1563
1564 //==========================================================================
1565 //
1566 // QualifyMap
1567 //
1568 //==========================================================================
1569
1570 static int QualifyMap(int map)
1571 {
1572         return (map < 1 || map > MapCount) ? 0 : map;
1573 }
1574
1575 //==========================================================================
1576 //
1577 // P_Init
1578 //
1579 //==========================================================================
1580
1581 void P_Init(void)
1582 {
1583         InitMapInfo();
1584         P_InitSwitchList();
1585         P_InitFTAnims(); // Init flat and texture animations
1586         P_InitTerrainTypes();
1587         P_InitLava();
1588         R_InitSprites(sprnames);
1589 }
1590
1591
1592 // Special early initializer needed to start sound before R_Init()
1593 void InitMapMusicInfo(void)
1594 {
1595         int i;
1596
1597         for (i=0; i<99; i++)
1598         {
1599                 strcpy(MapInfo[i].songLump, DEFAULT_SONG_LUMP);
1600         }
1601         MapCount = 98;
1602 }
1603
1604 /*
1605 void My_Debug(void)
1606 {
1607         int i;
1608
1609         printf("My debug stuff ----------------------\n");
1610         printf("gamemap=%d\n",gamemap);
1611         for (i=0; i<10; i++)
1612         {
1613                 printf("i=%d  songlump=%s\n",i,MapInfo[i].songLump);
1614         }
1615 }
1616 */