11 float AccurateDistance(fixed_t dx,fixed_t dy);
14 void P_SpawnMapThing (mapthing_t *mthing);
26 subsector_t *subsectors;
37 short *blockmaplump; // offsets in blockmap are from here
39 int bmapwidth, bmapheight; // in mapblocks
40 fixed_t bmaporgx, bmaporgy; // origin of block map
41 mobj_t **blocklinks; // for thing chains
43 byte *rejectmatrix; // for fast sight rejection
45 mapthing_t deathmatchstarts[10], *deathmatch_p;
46 mapthing_t playerstarts[MAXPLAYERS];
56 void P_LoadVertexes (int lump)
63 numvertexes = W_LumpLength (lump) / sizeof(mapvertex_t);
64 vertexes = Z_Malloc (numvertexes*sizeof(vertex_t),PU_LEVEL,0);
65 data = W_CacheLumpNum (lump,PU_STATIC);
67 ml = (mapvertex_t *)data;
69 for (i=0 ; i<numvertexes ; i++, li++, ml++)
71 li->x = SHORT(ml->x)<<FRACBITS;
72 li->y = SHORT(ml->y)<<FRACBITS;
87 void P_LoadSegs (int lump)
96 numsegs = W_LumpLength (lump) / sizeof(mapseg_t);
97 segs = Z_Malloc (numsegs*sizeof(seg_t),PU_LEVEL,0);
98 memset (segs, 0, numsegs*sizeof(seg_t));
99 data = W_CacheLumpNum (lump,PU_STATIC);
101 ml = (mapseg_t *)data;
103 for (i=0 ; i<numsegs ; i++, li++, ml++)
105 li->v1 = &vertexes[SHORT(ml->v1)];
106 li->v2 = &vertexes[SHORT(ml->v2)];
108 li->angle = (SHORT(ml->angle))<<16;
109 li->offset = (SHORT(ml->offset))<<16;
110 linedef = SHORT(ml->linedef);
111 ldef = &lines[linedef];
113 side = SHORT(ml->side);
114 li->sidedef = &sides[ldef->sidenum[side]];
115 li->frontsector = sides[ldef->sidenum[side]].sector;
116 if (ldef-> flags & ML_TWOSIDED)
117 li->backsector = sides[ldef->sidenum[side^1]].sector;
121 // Calculate the length of the segment. We need this for
122 // the texture coordinates. -jk
123 li->len = AccurateDistance( li->v2->x - li->v1->x,
124 li->v2->y - li->v1->y );
140 void P_LoadSubsectors (int lump)
147 numsubsectors = W_LumpLength (lump) / sizeof(mapsubsector_t);
148 subsectors = Z_Malloc (numsubsectors*sizeof(subsector_t),PU_LEVEL,0);
149 data = W_CacheLumpNum (lump,PU_STATIC);
151 ms = (mapsubsector_t *)data;
152 memset (subsectors,0, numsubsectors*sizeof(subsector_t));
154 for (i=0 ; i<numsubsectors ; i++, ss++, ms++)
156 ss->numlines = SHORT(ms->numsegs);
157 ss->firstline = SHORT(ms->firstseg);
172 void P_LoadSectors (int lump)
179 numsectors = W_LumpLength (lump) / sizeof(mapsector_t);
180 sectors = Z_Malloc (numsectors*sizeof(sector_t),PU_LEVEL,0);
181 memset (sectors, 0, numsectors*sizeof(sector_t));
182 data = W_CacheLumpNum (lump,PU_STATIC);
184 ms = (mapsector_t *)data;
186 for (i=0 ; i<numsectors ; i++, ss++, ms++)
188 ss->floorheight = SHORT(ms->floorheight)<<FRACBITS;
189 ss->ceilingheight = SHORT(ms->ceilingheight)<<FRACBITS;
190 ss->floorpic = R_FlatNumForName(ms->floorpic);
191 ss->ceilingpic = R_FlatNumForName(ms->ceilingpic);
192 ss->lightlevel = SHORT(ms->lightlevel);
193 ss->special = SHORT(ms->special);
194 ss->tag = SHORT(ms->tag);
195 ss->thinglist = NULL;
197 ss->flatoffx = ss->flatoffy = 0; // Flat scrolling.
198 ss->skyfix = 0; // Set if needed.
214 void P_LoadNodes (int lump)
221 numnodes = W_LumpLength (lump) / sizeof(mapnode_t);
222 nodes = Z_Malloc (numnodes*sizeof(node_t),PU_LEVEL,0);
223 data = W_CacheLumpNum (lump,PU_STATIC);
225 mn = (mapnode_t *)data;
227 for (i=0 ; i<numnodes ; i++, no++, mn++)
229 no->x = SHORT(mn->x)<<FRACBITS;
230 no->y = SHORT(mn->y)<<FRACBITS;
231 no->dx = SHORT(mn->dx)<<FRACBITS;
232 no->dy = SHORT(mn->dy)<<FRACBITS;
233 for (j=0 ; j<2 ; j++)
235 no->children[j] = SHORT(mn->children[j]);
236 for (k=0 ; k<4 ; k++)
237 no->bbox[j][k] = SHORT(mn->bbox[j][k])<<FRACBITS;
254 void P_LoadThings (int lump)
261 data = W_CacheLumpNum (lump,PU_STATIC);
262 numthings = W_LumpLength (lump) / sizeof(mapthing_t);
264 mt = (mapthing_t *)data;
265 for (i=0 ; i<numthings ; i++, mt++)
267 mt->x = SHORT(mt->x);
268 mt->y = SHORT(mt->y);
269 mt->angle = SHORT(mt->angle);
270 mt->type = SHORT(mt->type);
271 mt->options = SHORT(mt->options);
272 P_SpawnMapThing (mt);
285 = Also counts secret lines for intermissions
289 void P_LoadLineDefs (int lump)
297 numlines = W_LumpLength (lump) / sizeof(maplinedef_t);
298 lines = Z_Malloc (numlines*sizeof(line_t),PU_LEVEL,0);
299 memset (lines, 0, numlines*sizeof(line_t));
300 data = W_CacheLumpNum (lump,PU_STATIC);
302 mld = (maplinedef_t *)data;
304 for (i=0 ; i<numlines ; i++, mld++, ld++)
306 ld->flags = SHORT(mld->flags);
307 ld->special = SHORT(mld->special);
308 ld->tag = SHORT(mld->tag);
309 v1 = ld->v1 = &vertexes[SHORT(mld->v1)];
310 v2 = ld->v2 = &vertexes[SHORT(mld->v2)];
311 ld->dx = v2->x - v1->x;
312 ld->dy = v2->y - v1->y;
314 ld->slopetype = ST_VERTICAL;
316 ld->slopetype = ST_HORIZONTAL;
319 if (FixedDiv (ld->dy , ld->dx) > 0)
320 ld->slopetype = ST_POSITIVE;
322 ld->slopetype = ST_NEGATIVE;
327 ld->bbox[BOXLEFT] = v1->x;
328 ld->bbox[BOXRIGHT] = v2->x;
332 ld->bbox[BOXLEFT] = v2->x;
333 ld->bbox[BOXRIGHT] = v1->x;
337 ld->bbox[BOXBOTTOM] = v1->y;
338 ld->bbox[BOXTOP] = v2->y;
342 ld->bbox[BOXBOTTOM] = v2->y;
343 ld->bbox[BOXTOP] = v1->y;
345 ld->sidenum[0] = SHORT(mld->sidenum[0]);
346 ld->sidenum[1] = SHORT(mld->sidenum[1]);
347 if (ld->sidenum[0] != -1)
348 ld->frontsector = sides[ld->sidenum[0]].sector;
351 if (ld->sidenum[1] != -1)
352 ld->backsector = sides[ld->sidenum[1]].sector;
369 void P_LoadSideDefs (int lump)
376 numsides = W_LumpLength (lump) / sizeof(mapsidedef_t);
377 sides = Z_Malloc (numsides*sizeof(side_t),PU_LEVEL,0);
378 memset (sides, 0, numsides*sizeof(side_t));
379 data = W_CacheLumpNum (lump,PU_STATIC);
381 msd = (mapsidedef_t *)data;
383 for (i=0 ; i<numsides ; i++, msd++, sd++)
385 sd->textureoffset = SHORT(msd->textureoffset)<<FRACBITS;
386 sd->rowoffset = SHORT(msd->rowoffset)<<FRACBITS;
387 sd->toptexture = R_TextureNumForName(msd->toptexture);
388 sd->bottomtexture = R_TextureNumForName(msd->bottomtexture);
389 sd->midtexture = R_TextureNumForName(msd->midtexture);
390 sd->sector = §ors[SHORT(msd->sector)];
406 void P_LoadBlockMap (int lump)
410 blockmaplump = W_CacheLumpNum (lump,PU_LEVEL);
411 blockmap = blockmaplump+4;
412 count = W_LumpLength (lump)/2;
413 for (i=0 ; i<count ; i++)
414 blockmaplump[i] = SHORT(blockmaplump[i]);
416 bmaporgx = blockmaplump[0]<<FRACBITS;
417 bmaporgy = blockmaplump[1]<<FRACBITS;
418 bmapwidth = blockmaplump[2];
419 bmapheight = blockmaplump[3];
421 // clear out mobj chains
422 count = sizeof(*blocklinks)* bmapwidth*bmapheight;
423 blocklinks = Z_Malloc (count,PU_LEVEL, 0);
424 memset (blocklinks, 0, count);
435 = Builds sector line lists and subsector sector numbers
436 = Finds block bounding boxes for sectors
440 void P_GroupLines (void)
451 // look up sector number for each subsector
453 for (i=0 ; i<numsubsectors ; i++, ss++)
455 seg = &segs[ss->firstline];
456 ss->sector = seg->sidedef->sector;
459 // count number of lines in each sector
462 for (i=0 ; i<numlines ; i++, li++)
465 li->frontsector->linecount++;
466 if (li->backsector && li->backsector != li->frontsector)
468 li->backsector->linecount++;
473 // build line tables for each sector
474 linebuffer = Z_Malloc (total*4, PU_LEVEL, 0);
476 for (i=0 ; i<numsectors ; i++, sector++)
479 sector->lines = linebuffer;
481 for (j=0 ; j<numlines ; j++, li++)
483 if (li->frontsector == sector || li->backsector == sector)
486 M_AddToBox (bbox, li->v1->x, li->v1->y);
487 M_AddToBox (bbox, li->v2->x, li->v2->y);
490 if (linebuffer - sector->lines != sector->linecount)
491 I_Error ("P_GroupLines: miscounted");
493 // set the degenmobj_t to the middle of the bounding box
494 sector->soundorg.x = (bbox[BOXRIGHT]+bbox[BOXLEFT])/2;
495 sector->soundorg.y = (bbox[BOXTOP]+bbox[BOXBOTTOM])/2;
497 // adjust bounding box to map blocks
498 block = (bbox[BOXTOP]-bmaporgy+MAXRADIUS)>>MAPBLOCKSHIFT;
499 block = block >= bmapheight ? bmapheight-1 : block;
500 sector->blockbox[BOXTOP]=block;
502 block = (bbox[BOXBOTTOM]-bmaporgy-MAXRADIUS)>>MAPBLOCKSHIFT;
503 block = block < 0 ? 0 : block;
504 sector->blockbox[BOXBOTTOM]=block;
506 block = (bbox[BOXRIGHT]-bmaporgx+MAXRADIUS)>>MAPBLOCKSHIFT;
507 block = block >= bmapwidth ? bmapwidth-1 : block;
508 sector->blockbox[BOXRIGHT]=block;
510 block = (bbox[BOXLEFT]-bmaporgx-MAXRADIUS)>>MAPBLOCKSHIFT;
511 block = block < 0 ? 0 : block;
512 sector->blockbox[BOXLEFT]=block;
517 float AccurateDistance(fixed_t dx,fixed_t dy)
519 float fx = FIX2FLT(dx), fy = FIX2FLT(dy);
521 return (float)sqrt(fx*fx + fy*fy);
525 #define MAX_CC_SIDES 64
527 int detSideFloat(fvertex_t *pnt, fdivline_t *dline)
530 (AY-CY)(BX-AX)-(AX-CX)(BY-AY)
531 s = -----------------------------
534 If s<0 C is left of AB (you can just check the numerator)
535 If s>0 C is right of AB
538 // We'll return false if the point c is on the left side.
539 /* float ax = FIX2FLT(a->x), ay = FIX2FLT(a->y);
540 float bx = FIX2FLT(b->x), by = FIX2FLT(b->y);
541 float cx = FIX2FLT(c->x), cy = FIX2FLT(c->y);*/
542 //float ax = dline->x, ay = dline->y;
543 //float bx = ax + dline->dx, by = ay + dline->dy;
545 // REWRITE using dline->dx and dline->dy for (bx-ax) and (by-ay).
547 //float s = /*(*/(ay-pnt->y)*(bx-ax)-(ax-pnt->x)*(by-ay);//)/l2;
548 float s = (dline->y-pnt->y)*dline->dx-(dline->x-pnt->x)*dline->dy;
555 // Lines start-end and fdiv must intersect.
556 float findIntersectionVertex( fvertex_t *start, fvertex_t *end,
557 fdivline_t *fdiv, fvertex_t *inter )
559 float ax = start->x, ay = start->y, bx = end->x, by = end->y;
560 float cx = fdiv->x, cy = fdiv->y, dx = cx+fdiv->dx, dy = cy+fdiv->dy;
563 (YA-YC)(XD-XC)-(XA-XC)(YD-YC)
564 r = ----------------------------- (eqn 1)
565 (XB-XA)(YD-YC)-(YB-YA)(XD-XC)
568 float r = ((ay-cy)*(dx-cx)-(ax-cx)*(dy-cy)) /
569 ((bx-ax)*(dy-cy)-(by-ay)*(dx-cx));
574 inter->x = ax + r*(bx-ax);
575 inter->y = ay + r*(by-ay);
580 void P_ConvexCarver(subsector_t *ssec, int num, divline_t *list)
582 int numclippers = num+ssec->numlines;
583 fdivline_t *clippers = (fdivline_t*) Z_Malloc(numclippers*sizeof(fdivline_t), PU_STATIC, 0);
584 int i, k, numedgepoints;
585 fvertex_t *edgepoints;
586 unsigned char sidelist[MAX_CC_SIDES];
588 // Convert the divlines to float, in reverse order.
589 for(i=0; i<numclippers; i++)
593 clippers[i].x = FIX2FLT(list[num-i-1].x);
594 clippers[i].y = FIX2FLT(list[num-i-1].y);
595 clippers[i].dx = FIX2FLT(list[num-i-1].dx);
596 clippers[i].dy = FIX2FLT(list[num-i-1].dy);
600 seg_t *seg = segs+(ssec->firstline+i-num);
601 clippers[i].x = FIX2FLT(seg->v1->x);
602 clippers[i].y = FIX2FLT(seg->v1->y);
603 clippers[i].dx = FIX2FLT(seg->v2->x - seg->v1->x);
604 clippers[i].dy = FIX2FLT(seg->v2->y - seg->v1->y);
608 // Setup the 'worldwide' polygon.
610 edgepoints = (fvertex_t*)malloc(numedgepoints*sizeof(fvertex_t));
612 edgepoints[0].x = -32768;
613 edgepoints[0].y = 32768;
615 edgepoints[1].x = 32768;
616 edgepoints[1].y = 32768;
618 edgepoints[2].x = 32768;
619 edgepoints[2].y = -32768;
621 edgepoints[3].x = -32768;
622 edgepoints[3].y = -32768;
625 // We'll now clip the polygon with each of the divlines. The left side of
626 // each divline is discarded.
627 for(i=0; i<numclippers; i++)
629 fdivline_t *curclip = clippers+i;
631 // First we'll determine the side of each vertex. Points are allowed
632 // to be on the line.
633 for(k=0; k<numedgepoints; k++)
635 sidelist[k] = detSideFloat(edgepoints+k, curclip);
638 for(k=0; k<numedgepoints; k++)
640 int startIdx = k, endIdx = k+1;
642 // Check the end index.
643 if(endIdx == numedgepoints) endIdx = 0; // Wrap-around.
645 // Clipping will happen when the ends are on different sides.
646 if(sidelist[startIdx] != sidelist[endIdx])
649 // Find the intersection point of intersecting lines.
650 findIntersectionVertex(edgepoints+startIdx, edgepoints+endIdx,
653 // Add the new vertex. Also modify the sidelist.
655 (fvertex_t*)realloc(edgepoints,(++numedgepoints)*sizeof(fvertex_t));
656 if(numedgepoints >= MAX_CC_SIDES) I_Error("Too many points in carver.\n");
658 // Make room for the new vertex.
659 memmove(edgepoints+endIdx+1, edgepoints+endIdx,
660 (numedgepoints-endIdx-1)*sizeof(fvertex_t));
661 memcpy(edgepoints+endIdx, &newvert, sizeof(newvert));
663 memmove(sidelist+endIdx+1, sidelist+endIdx,
664 numedgepoints-endIdx-1);
665 sidelist[endIdx] = 1;
667 // Skip over the new vertex.
672 // Now we must discard the points that are on the wrong side.
673 for(k=0; k<numedgepoints; k++)
676 memmove(edgepoints+k, edgepoints+k+1,
677 (numedgepoints-k-1)*sizeof(fvertex_t));
678 memmove(sidelist+k, sidelist+k+1, numedgepoints-k-1);
686 //I_Error("All carved away!\n");
687 printf( "All carved away: subsector %p\n", ssec);
688 ssec->numedgeverts = 0;
690 ssec->origedgeverts = 0;
694 // Screen out consecutive identical points.
695 for(i=0; i<numedgepoints; i++)
698 if(previdx < 0) previdx = numedgepoints-1;
699 if(edgepoints[i].x == edgepoints[previdx].x
700 && edgepoints[i].y == edgepoints[previdx].y)
702 // This point (i) must be removed.
703 memmove(edgepoints+i, edgepoints+i+1,
704 sizeof(fvertex_t)*(numedgepoints-i-1));
709 // We need these with dynamic lights.
710 ssec->origedgeverts =
711 (fvertex_t*)Z_Malloc(sizeof(fvertex_t)*numedgepoints, PU_LEVEL, 0);
712 memcpy(ssec->origedgeverts, edgepoints, sizeof(fvertex_t)*numedgepoints);
714 // Find the center point. Do this by first finding the bounding box.
715 ssec->bbox[0].x = ssec->bbox[1].x = edgepoints[0].x;
716 ssec->bbox[0].y = ssec->bbox[1].y = edgepoints[0].y;
717 for(i=1; i<numedgepoints; i++)
719 if(edgepoints[i].x < ssec->bbox[0].x) ssec->bbox[0].x =
721 if(edgepoints[i].y < ssec->bbox[0].y) ssec->bbox[0].y =
723 if(edgepoints[i].x > ssec->bbox[1].x) ssec->bbox[1].x =
725 if(edgepoints[i].y > ssec->bbox[1].y) ssec->bbox[1].y =
728 ssec->midpoint.x = (ssec->bbox[1].x+ssec->bbox[0].x)/2;
729 ssec->midpoint.y = (ssec->bbox[1].y+ssec->bbox[0].y)/2;
731 // Make slight adjustments to patch up those ugly, small gaps.
732 for(i=0; i<numedgepoints; i++)
734 float dx = edgepoints[i].x - ssec->midpoint.x,
735 dy = edgepoints[i].y - ssec->midpoint.y;
736 float dlen = (float) sqrt(dx*dx + dy*dy) * 3;
739 edgepoints[i].x += dx/dlen;
740 edgepoints[i].y += dy/dlen;
744 ssec->numedgeverts = numedgepoints;
746 (fvertex_t*)Z_Malloc(sizeof(fvertex_t)*numedgepoints,PU_LEVEL,0);
747 memcpy(ssec->edgeverts, edgepoints, sizeof(fvertex_t)*numedgepoints);
750 // We're done, free the edgepoints memory.
756 void P_CreateFloorsAndCeilings( int bspnode, int numdivlines,
757 divline_t* divlines )
760 divline_t *childlist, *dl;
761 int childlistsize = numdivlines+1;
763 // If this is a subsector we are dealing with, begin carving with the
765 if(bspnode & NF_SUBSECTOR)
768 // We have arrived at a subsector. The divline list contains all
769 // the partition lines that carve out the subsector.
771 //printf( "subsector %d: %d
772 //divlines\n",bspnode&(~NF_SUBSECTOR),numdivlines);
774 int ssidx = bspnode & (~NF_SUBSECTOR);
776 P_ConvexCarver(subsectors+ssidx, numdivlines, divlines);
778 //printf( "subsector %d: %d edgeverts\n", ssidx,
779 //subsectors[ssidx].numedgeverts);
780 // This leaf is done.
784 // Get a pointer to the node.
785 nod = nodes + bspnode;
787 // Allocate a new list for each child.
788 childlist = (divline_t*)malloc(childlistsize*sizeof(divline_t));
790 // Copy the previous lines.
791 if(divlines) memcpy(childlist,divlines,numdivlines*sizeof(divline_t));
793 dl = childlist + numdivlines;
796 // The right child gets the original line (LEFT side clipped).
799 P_CreateFloorsAndCeilings(nod->children[0],childlistsize,childlist);
801 // The left side. We must reverse the line, otherwise the wrong
802 // side would get clipped.
805 P_CreateFloorsAndCeilings(nod->children[1],childlistsize,childlist);
807 // We are finishing with this node, free the allocated list.
816 // We need to check all the linedefs.
817 for(i=0; i<numlines; i++)
819 line_t *line = lines + i;
820 sector_t *front = line->frontsector, *back = line->backsector;
823 if(!front || !back) continue;
824 // Both the front and back sectors must have the sky ceiling.
825 if(front->ceilingpic != skyflatnum || back->ceilingpic != skyflatnum)
827 // Operate on the lower sector.
828 /*ST_Message("Line %d (f:%d, b:%d).\n", i, front->ceilingheight >>
830 back->ceilingheight >> FRACBITS);*/
831 if(front->ceilingheight < back->ceilingheight)
833 fix = (back->ceilingheight-front->ceilingheight) >> FRACBITS;
834 if(fix > front->skyfix) front->skyfix = fix;
836 else if(front->ceilingheight > back->ceilingheight)
838 fix = (front->ceilingheight-back->ceilingheight) >> FRACBITS;
839 if(fix > back->skyfix) back->skyfix = fix;
845 //=============================================================================
856 void P_SetupLevel (int episode, int map, int playermask, skill_t skill)
864 totalkills = totalitems = totalsecret = 0;
865 for (i=0 ; i<MAXPLAYERS ; i++)
867 players[i].killcount = players[i].secretcount
868 = players[i].itemcount = 0;
870 players[consoleplayer].viewz = 1; // will be set by player think
872 S_Start (); // make sure all sounds are stopped before Z_FreeTags
874 Z_FreeTags (PU_LEVEL, PU_PURGELEVEL-1);
883 // look for a regular (development) map first
886 lumpname[1] = '0' + episode;
888 lumpname[3] = '0' + map;
892 lumpnum = W_GetNumForName (lumpname);
894 // note: most of this ordering is important
895 P_LoadBlockMap (lumpnum+ML_BLOCKMAP);
896 P_LoadVertexes (lumpnum+ML_VERTEXES);
897 P_LoadSectors (lumpnum+ML_SECTORS);
898 P_LoadSideDefs (lumpnum+ML_SIDEDEFS);
900 P_LoadLineDefs (lumpnum+ML_LINEDEFS);
901 P_LoadSubsectors (lumpnum+ML_SSECTORS);
902 P_LoadNodes (lumpnum+ML_NODES);
903 P_LoadSegs (lumpnum+ML_SEGS);
906 // We need to carve out the floor/ceiling polygons of each subsector.
907 // Walk the tree to do this.
908 //ST_Message( "Floor/ceiling creation: begin at %d, ", ticcount);
909 P_CreateFloorsAndCeilings(numnodes-1, 0, 0);
910 // Also check if the sky needs a fix.
914 rejectmatrix = W_CacheLumpNum (lumpnum+ML_REJECT,PU_LEVEL);
918 deathmatch_p = deathmatchstarts;
919 P_InitAmbientSound();
922 P_LoadThings(lumpnum+ML_THINGS);
926 // if deathmatch, randomly spawn the active players
931 for (i=0 ; i<MAXPLAYERS ; i++)
934 { // must give a player spot before deathmatchspawn
935 mobj = P_SpawnMobj (playerstarts[i].x<<16,
936 playerstarts[i].y<<16,0, MT_PLAYER);
937 players[i].mo = mobj;
938 G_DeathMatchSpawnPlayer (i);
942 parm = M_CheckParm("-timer");
943 if(parm && parm < myargc-1)
945 TimerGame = atoi(myargv[parm+1])*35*60;
949 // set up world state
952 // build subsector connect matrix
953 // P_ConnectSubsectors ();
959 //printf ("free memory: 0x%x\n", Z_FreeMemory());
976 P_InitTerrainTypes();
978 R_InitSprites(sprnames);