mirror of
https://github.com/ZDoom/gzdoom.git
synced 2025-04-25 20:20:57 +00:00
1433 lines
38 KiB
C
1433 lines
38 KiB
C
// Emacs style mode select -*- C++ -*-
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// $Id:$
|
|
//
|
|
// Copyright (C) 1993-1996 by id Software, Inc.
|
|
//
|
|
// This source is available for distribution and/or modification
|
|
// only under the terms of the DOOM Source Code License as
|
|
// published by id Software. All rights reserved.
|
|
//
|
|
// The source is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
|
|
// for more details.
|
|
//
|
|
// $Log:$
|
|
//
|
|
// DESCRIPTION:
|
|
// Do all the WAD I/O, get map description,
|
|
// set up initial state and misc. LUTs.
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
#include <math.h>
|
|
|
|
#include "m_alloc.h"
|
|
#include "m_argv.h"
|
|
#include "z_zone.h"
|
|
#include "m_swap.h"
|
|
#include "m_bbox.h"
|
|
#include "g_game.h"
|
|
#include "i_system.h"
|
|
#include "w_wad.h"
|
|
#include "doomdef.h"
|
|
#include "p_local.h"
|
|
#include "p_effect.h"
|
|
#include "s_sound.h"
|
|
#include "doomstat.h"
|
|
#include "p_lnspec.h"
|
|
#include "v_palett.h"
|
|
|
|
|
|
extern void P_SpawnMapThing (mapthing2_t *mthing, int position);
|
|
|
|
extern void P_TranslateLineDef (line_t *ld, maplinedef_t *mld);
|
|
extern void P_TranslateTeleportThings (void);
|
|
extern int P_TranslateSectorSpecial (int);
|
|
|
|
|
|
//
|
|
// MAP related Lookup tables.
|
|
// Store VERTEXES, LINEDEFS, SIDEDEFS, etc.
|
|
//
|
|
int numvertexes;
|
|
vertex_t* vertexes;
|
|
|
|
int numsegs;
|
|
seg_t* segs;
|
|
|
|
int numsectors;
|
|
sector_t* sectors;
|
|
|
|
int numsubsectors;
|
|
subsector_t* subsectors;
|
|
|
|
int numnodes;
|
|
node_t* nodes;
|
|
|
|
int numlines;
|
|
line_t* lines;
|
|
|
|
int numsides;
|
|
side_t* sides;
|
|
|
|
// [RH] Set true if the map contains a BEHAVIOR lump
|
|
BOOL HasBehavior;
|
|
|
|
|
|
// BLOCKMAP
|
|
// Created from axis aligned bounding box
|
|
// of the map, a rectangular array of
|
|
// blocks of size ...
|
|
// Used to speed up collision detection
|
|
// by spatial subdivision in 2D.
|
|
//
|
|
// Blockmap size.
|
|
int bmapwidth;
|
|
int bmapheight; // size in mapblocks
|
|
|
|
int *blockmap; // int for larger maps ([RH] Made int because BOOM does)
|
|
int *blockmaplump; // offsets in blockmap are from here
|
|
|
|
fixed_t bmaporgx; // origin of block map
|
|
fixed_t bmaporgy;
|
|
|
|
mobj_t** blocklinks; // for thing chains
|
|
|
|
|
|
|
|
// REJECT
|
|
// For fast sight rejection.
|
|
// Speeds up enemy AI by skipping detailed
|
|
// LineOf Sight calculation.
|
|
// Without special effect, this could be
|
|
// used as a PVS lookup as well.
|
|
//
|
|
byte* rejectmatrix;
|
|
BOOL rejectempty;
|
|
|
|
|
|
// Maintain single and multi player starting spots.
|
|
int MaxDeathmatchStarts;
|
|
mapthing2_t *deathmatchstarts;
|
|
mapthing2_t *deathmatch_p;
|
|
mapthing2_t playerstarts[MAXPLAYERS];
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
// P_LoadVertexes
|
|
//
|
|
void P_LoadVertexes (int lump)
|
|
{
|
|
byte *data;
|
|
int i;
|
|
|
|
// Determine number of vertices:
|
|
// total lump length / vertex record length.
|
|
numvertexes = W_LumpLength (lump) / sizeof(mapvertex_t);
|
|
|
|
// Allocate zone memory for buffer.
|
|
vertexes = Z_Malloc (numvertexes*sizeof(vertex_t), PU_LEVEL, 0);
|
|
|
|
// Load data into cache.
|
|
data = W_CacheLumpNum (lump, PU_STATIC);
|
|
|
|
// Copy and convert vertex coordinates,
|
|
// internal representation as fixed.
|
|
for (i = 0; i < numvertexes; i++)
|
|
{
|
|
vertexes[i].x = SHORT(((mapvertex_t *)data)[i].x)<<FRACBITS;
|
|
vertexes[i].y = SHORT(((mapvertex_t *)data)[i].y)<<FRACBITS;
|
|
}
|
|
|
|
// Free buffer memory.
|
|
Z_Free (data);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// P_LoadSegs
|
|
//
|
|
// killough 5/3/98: reformatted, cleaned up
|
|
|
|
void P_LoadSegs (int lump)
|
|
{
|
|
int i;
|
|
byte *data;
|
|
byte *vertchanged = Z_Malloc(numvertexes,PU_LEVEL,0); // phares 10/4/98
|
|
line_t* line; // phares 10/4/98
|
|
int ptp_angle; // phares 10/4/98
|
|
int delta_angle; // phares 10/4/98
|
|
int dis; // phares 10/4/98
|
|
int dx,dy; // phares 10/4/98
|
|
int vnum1,vnum2; // phares 10/4/98
|
|
|
|
memset(vertchanged,0,numvertexes); // phares 10/4/98
|
|
|
|
numsegs = W_LumpLength(lump) / sizeof(mapseg_t);
|
|
segs = Z_Malloc(numsegs*sizeof(seg_t),PU_LEVEL,0);
|
|
memset(segs, 0, numsegs*sizeof(seg_t));
|
|
data = W_CacheLumpNum(lump,PU_STATIC);
|
|
|
|
// phares: 10/4/98: Vertchanged is an array that represents the vertices.
|
|
// Mark those used by linedefs. A marked vertex is one that is not a
|
|
// candidate for movement further down.
|
|
|
|
line = lines;
|
|
for (i = 0; i < numlines ; i++,line++)
|
|
{
|
|
vertchanged[line->v1 - vertexes] = vertchanged[line->v2 - vertexes] = 1;
|
|
}
|
|
|
|
for (i = 0; i < numsegs; i++)
|
|
{
|
|
seg_t *li = segs+i;
|
|
mapseg_t *ml = (mapseg_t *) data + i;
|
|
|
|
int side, linedef;
|
|
line_t *ldef;
|
|
|
|
li->v1 = &vertexes[SHORT(ml->v1)];
|
|
li->v2 = &vertexes[SHORT(ml->v2)];
|
|
|
|
li->angle = (SHORT(ml->angle))<<16;
|
|
|
|
// phares 10/4/98: In the case of a lineseg that was created by splitting
|
|
// another line, it appears that the line angle is inherited from the
|
|
// father line. Due to roundoff, the new vertex may have been placed 'off
|
|
// the line'. When you get close to such a line, and it is very short,
|
|
// it's possible that the roundoff error causes 'firelines', the thin
|
|
// lines that can draw from screen top to screen bottom occasionally. This
|
|
// is due to all the angle calculations that are done based on the line
|
|
// angle, the angles from the viewer to the vertices, and the viewer's
|
|
// angle in the world. In the case of firelines, the rounded-off position
|
|
// of one of the vertices determines one of these angles, and introduces
|
|
// an error in the scaling factor for mapping textures and determining
|
|
// where on the screen the ceiling and floor spans should be shown. For a
|
|
// fireline, the engine thinks the ceiling bottom and floor top are at the
|
|
// midpoint of the screen. So you get ceilings drawn all the way down to the
|
|
// screen midpoint, and floors drawn all the way up. Thus 'firelines'. The
|
|
// name comes from the original sighting, which involved a fire texture.
|
|
//
|
|
// To correct this, reset the vertex that was added so that it sits ON the
|
|
// split line.
|
|
//
|
|
// To know which of the two vertices was added, its number is greater than
|
|
// that of the last of the author-created vertices. If both vertices of the
|
|
// line were added by splitting, pick the higher-numbered one. Once you've
|
|
// changed a vertex, don't change it again if it shows up in another seg.
|
|
//
|
|
// To determine if there's an error in the first place, find the
|
|
// angle of the line between the two seg vertices. If it's one degree or more
|
|
// off, then move one vertex. This may seem insignificant, but one degree
|
|
// errors _can_ cause firelines.
|
|
|
|
ptp_angle = R_PointToAngle2(li->v1->x,li->v1->y,li->v2->x,li->v2->y);
|
|
dis = 0;
|
|
delta_angle = (abs(ptp_angle-li->angle)>>ANGLETOFINESHIFT)*360/8192;
|
|
|
|
if (delta_angle != 0)
|
|
{
|
|
dx = (li->v1->x - li->v2->x)>>FRACBITS;
|
|
dy = (li->v1->y - li->v2->y)>>FRACBITS;
|
|
dis = ((int) sqrt(dx*dx + dy*dy))<<FRACBITS;
|
|
dx = finecosine[li->angle>>ANGLETOFINESHIFT];
|
|
dy = finesine[li->angle>>ANGLETOFINESHIFT];
|
|
vnum1 = li->v1 - vertexes;
|
|
vnum2 = li->v2 - vertexes;
|
|
if ((vnum2 > vnum1) && (vertchanged[vnum2] == 0))
|
|
{
|
|
li->v2->x = li->v1->x + FixedMul(dis,dx);
|
|
li->v2->y = li->v1->y + FixedMul(dis,dy);
|
|
vertchanged[vnum2] = 1; // this was changed
|
|
}
|
|
else if (vertchanged[vnum1] == 0)
|
|
{
|
|
li->v1->x = li->v2->x - FixedMul(dis,dx);
|
|
li->v1->y = li->v2->y - FixedMul(dis,dy);
|
|
vertchanged[vnum1] = 1; // this was changed
|
|
}
|
|
}
|
|
|
|
li->offset = (SHORT(ml->offset))<<16;
|
|
linedef = SHORT(ml->linedef);
|
|
ldef = &lines[linedef];
|
|
li->linedef = ldef;
|
|
side = SHORT(ml->side);
|
|
li->sidedef = &sides[ldef->sidenum[side]];
|
|
li->frontsector = sides[ldef->sidenum[side]].sector;
|
|
|
|
// killough 5/3/98: ignore 2s flag if second sidedef missing:
|
|
if (ldef->flags & ML_TWOSIDED && ldef->sidenum[side^1]!=-1)
|
|
li->backsector = sides[ldef->sidenum[side^1]].sector;
|
|
else {
|
|
li->backsector = 0;
|
|
// [RH] And clear it, since it will crash in p_sight.c if the line comes into view
|
|
ldef->flags &= ~ML_TWOSIDED;
|
|
}
|
|
}
|
|
|
|
Z_Free (data);
|
|
Z_Free(vertchanged); // phares 10/4/98
|
|
}
|
|
|
|
|
|
//
|
|
// P_LoadSubsectors
|
|
//
|
|
void P_LoadSubsectors (int lump)
|
|
{
|
|
byte *data;
|
|
int i;
|
|
|
|
numsubsectors = W_LumpLength (lump) / sizeof(mapsubsector_t);
|
|
subsectors = Z_Malloc (numsubsectors*sizeof(subsector_t),PU_LEVEL,0);
|
|
data = W_CacheLumpNum (lump,PU_STATIC);
|
|
|
|
memset (subsectors, 0, numsubsectors*sizeof(subsector_t));
|
|
|
|
for (i = 0; i < numsubsectors; i++)
|
|
{
|
|
subsectors[i].numlines = SHORT(((mapsubsector_t *)data)[i].numsegs);
|
|
subsectors[i].firstline = SHORT(((mapsubsector_t *)data)[i].firstseg);
|
|
}
|
|
|
|
Z_Free (data);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// P_LoadSectors
|
|
//
|
|
void P_LoadSectors (int lump)
|
|
{
|
|
byte* data;
|
|
int i;
|
|
mapsector_t* ms;
|
|
sector_t* ss;
|
|
int defSeqType;
|
|
|
|
numsectors = W_LumpLength (lump) / sizeof(mapsector_t);
|
|
sectors = Z_Malloc (numsectors*sizeof(sector_t), PU_LEVEL, 0);
|
|
memset (sectors, 0, numsectors*sizeof(sector_t));
|
|
data = W_CacheLumpNum (lump, PU_STATIC);
|
|
|
|
if (level.flags & LEVEL_SNDSEQTOTALCTRL)
|
|
defSeqType = 0;
|
|
else
|
|
defSeqType = -1;
|
|
|
|
ms = (mapsector_t *)data;
|
|
ss = sectors;
|
|
for (i = 0; i < numsectors; i++, ss++, ms++)
|
|
{
|
|
ss->floorheight = SHORT(ms->floorheight)<<FRACBITS;
|
|
ss->ceilingheight = SHORT(ms->ceilingheight)<<FRACBITS;
|
|
ss->floorpic = (short)R_FlatNumForName(ms->floorpic);
|
|
ss->ceilingpic = (short)R_FlatNumForName(ms->ceilingpic);
|
|
ss->lightlevel = SHORT(ms->lightlevel);
|
|
if (HasBehavior)
|
|
ss->special = SHORT(ms->special);
|
|
else // [RH] Translate to new sector special
|
|
ss->special = P_TranslateSectorSpecial (SHORT(ms->special));
|
|
ss->tag = SHORT(ms->tag);
|
|
ss->thinglist = NULL;
|
|
ss->touching_thinglist = NULL; // phares 3/14/98
|
|
ss->seqType = defSeqType;
|
|
ss->nextsec = -1; //jff 2/26/98 add fields to support locking out
|
|
ss->prevsec = -1; // stair retriggering until build completes
|
|
|
|
// killough 3/7/98:
|
|
ss->floor_xoffs = 0;
|
|
ss->floor_yoffs = 0; // floor and ceiling flats offsets
|
|
ss->ceiling_xoffs = 0;
|
|
ss->ceiling_yoffs = 0;
|
|
ss->heightsec = -1; // sector used to get floor and ceiling height
|
|
ss->floorlightsec = -1; // sector used to get floor lighting
|
|
// killough 3/7/98: end changes
|
|
|
|
// killough 4/11/98 sector used to get ceiling lighting:
|
|
ss->ceilinglightsec = -1;
|
|
|
|
ss->gravity = 1.0f; // [RH] Default sector gravity of 1.0
|
|
|
|
// [RH] Sectors default to white light with the default fade.
|
|
// If they are outside (have a sky ceiling), they use the outside fog.
|
|
if (level.outsidefog != 0xff000000 && ss->ceilingpic == skyflatnum)
|
|
ss->colormap = GetSpecialLights (255,255,255,
|
|
RPART(level.outsidefog),GPART(level.outsidefog),BPART(level.outsidefog));
|
|
else
|
|
ss->colormap = GetSpecialLights (255,255,255,
|
|
RPART(level.fadeto),GPART(level.fadeto),BPART(level.fadeto));
|
|
}
|
|
|
|
Z_Free (data);
|
|
}
|
|
|
|
|
|
//
|
|
// P_LoadNodes
|
|
//
|
|
void P_LoadNodes (int lump)
|
|
{
|
|
byte* data;
|
|
int i;
|
|
int j;
|
|
int k;
|
|
mapnode_t* mn;
|
|
node_t* no;
|
|
|
|
numnodes = W_LumpLength (lump) / sizeof(mapnode_t);
|
|
nodes = Z_Malloc (numnodes*sizeof(node_t),PU_LEVEL,0);
|
|
data = W_CacheLumpNum (lump,PU_STATIC);
|
|
|
|
mn = (mapnode_t *)data;
|
|
no = nodes;
|
|
|
|
for (i = 0; i < numnodes; i++, no++, mn++)
|
|
{
|
|
no->x = SHORT(mn->x)<<FRACBITS;
|
|
no->y = SHORT(mn->y)<<FRACBITS;
|
|
no->dx = SHORT(mn->dx)<<FRACBITS;
|
|
no->dy = SHORT(mn->dy)<<FRACBITS;
|
|
for (j = 0; j < 2; j++)
|
|
{
|
|
no->children[j] = SHORT(mn->children[j]);
|
|
for (k = 0; k < 4; k++)
|
|
no->bbox[j][k] = SHORT(mn->bbox[j][k])<<FRACBITS;
|
|
}
|
|
}
|
|
|
|
Z_Free (data);
|
|
}
|
|
|
|
|
|
//
|
|
// P_LoadThings
|
|
//
|
|
void P_LoadThings (int lump)
|
|
{
|
|
mapthing2_t mt2; // [RH] for translation
|
|
byte *data = W_CacheLumpNum (lump, PU_STATIC);
|
|
mapthing_t *mt = (mapthing_t *)data;
|
|
mapthing_t *lastmt = (mapthing_t *)(data + W_LumpLength (lump));
|
|
|
|
// [RH] ZDoom now uses Hexen-style maps as its native format.
|
|
// Since this is the only place where Doom-style Things are ever
|
|
// referenced, we translate them into a Hexen-style thing.
|
|
memset (&mt2, 0, sizeof(mt2));
|
|
|
|
for ( ; mt < lastmt; mt++)
|
|
{
|
|
// [RH] At this point, monsters unique to Doom II were weeded out
|
|
// if the IWAD wasn't for Doom II. R_SpawnMapThing() can now
|
|
// handle these and more cases better, so we just pass it
|
|
// everything and let it decide what to do with them.
|
|
|
|
// [RH] Need to translate the spawn flags to Hexen format.
|
|
short flags = SHORT(mt->options);
|
|
mt2.flags = (short)((flags & 0xf) | 0x7e0);
|
|
if (flags & BTF_NOTSINGLE) mt2.flags &= ~MTF_SINGLE;
|
|
if (flags & BTF_NOTDEATHMATCH) mt2.flags &= ~MTF_DEATHMATCH;
|
|
if (flags & BTF_NOTCOOPERATIVE) mt2.flags &= ~MTF_COOPERATIVE;
|
|
|
|
mt2.x = SHORT(mt->x);
|
|
mt2.y = SHORT(mt->y);
|
|
mt2.angle = SHORT(mt->angle);
|
|
mt2.type = SHORT(mt->type);
|
|
|
|
P_SpawnMapThing (&mt2, 0);
|
|
}
|
|
|
|
Z_Free (data);
|
|
}
|
|
|
|
// [RH]
|
|
// P_LoadThings2
|
|
//
|
|
// Same as P_LoadThings() except it assumes Things are
|
|
// saved Hexen-style. Position also controls which single-
|
|
// player start spots are spawned by filtering out those
|
|
// whose first parameter don't match position.
|
|
//
|
|
void P_LoadThings2 (int lump, int position)
|
|
{
|
|
byte *data = W_CacheLumpNum (lump, PU_STATIC);
|
|
mapthing2_t *mt = (mapthing2_t *)data;
|
|
mapthing2_t *lastmt = (mapthing2_t *)(data + W_LumpLength (lump));
|
|
|
|
for ( ; mt < lastmt; mt++)
|
|
{
|
|
// [RH] At this point, monsters unique to Doom II were weeded out
|
|
// if the IWAD wasn't for Doom II. R_SpawnMapThing() can now
|
|
// handle these and more cases better, so we just pass it
|
|
// everything and let it decide what to do with them.
|
|
|
|
mt->thingid = SHORT(mt->thingid);
|
|
mt->x = SHORT(mt->x);
|
|
mt->y = SHORT(mt->y);
|
|
mt->z = SHORT(mt->z);
|
|
mt->angle = SHORT(mt->angle);
|
|
mt->type = SHORT(mt->type);
|
|
mt->flags = SHORT(mt->flags);
|
|
|
|
P_SpawnMapThing (mt, position);
|
|
}
|
|
|
|
Z_Free (data);
|
|
}
|
|
|
|
|
|
//
|
|
// P_LoadLineDefs
|
|
//
|
|
// killough 4/4/98: split into two functions, to allow sidedef overloading
|
|
//
|
|
// [RH] Actually split into four functions to allow for Hexen and Doom
|
|
// linedefs.
|
|
void P_AdjustLine (line_t *ld)
|
|
{
|
|
vertex_t *v1, *v2;
|
|
|
|
ld->lucency = 255; // [RH] Opaque by default
|
|
|
|
v1 = ld->v1;
|
|
v2 = ld->v2;
|
|
|
|
ld->dx = v2->x - v1->x;
|
|
ld->dy = v2->y - v1->y;
|
|
|
|
if (ld->dx == 0)
|
|
ld->slopetype = ST_VERTICAL;
|
|
else if (ld->dy == 0)
|
|
ld->slopetype = ST_HORIZONTAL;
|
|
else
|
|
ld->slopetype = (FixedDiv (ld->dy , ld->dx) > 0) ? ST_POSITIVE : ST_NEGATIVE;
|
|
|
|
if (v1->x < v2->x)
|
|
{
|
|
ld->bbox[BOXLEFT] = v1->x;
|
|
ld->bbox[BOXRIGHT] = v2->x;
|
|
}
|
|
else
|
|
{
|
|
ld->bbox[BOXLEFT] = v2->x;
|
|
ld->bbox[BOXRIGHT] = v1->x;
|
|
}
|
|
|
|
if (v1->y < v2->y)
|
|
{
|
|
ld->bbox[BOXBOTTOM] = v1->y;
|
|
ld->bbox[BOXTOP] = v2->y;
|
|
}
|
|
else
|
|
{
|
|
ld->bbox[BOXBOTTOM] = v2->y;
|
|
ld->bbox[BOXTOP] = v1->y;
|
|
}
|
|
|
|
// [RH] Set line id (as appropriate) here
|
|
if (ld->special == Line_SetIdentification ||
|
|
ld->special == Teleport_Line ||
|
|
ld->special == TranslucentLine ||
|
|
ld->special == Scroll_Texture_Model) {
|
|
ld->id = ld->args[0];
|
|
}
|
|
// killough 4/4/98: support special sidedef interpretation below
|
|
if ((ld->sidenum[0] != -1)
|
|
|
|
// [RH] Save Static_Init only if it's interested in the textures
|
|
&& ( (ld->special == Static_Init && ld->args[1] == Init_Color)
|
|
|| ld->special != Static_Init) ) {
|
|
sides[*ld->sidenum].special = ld->special;
|
|
sides[*ld->sidenum].tag = ld->args[0];
|
|
}
|
|
else
|
|
sides[*ld->sidenum].special = 0;
|
|
}
|
|
|
|
// killough 4/4/98: delay using sidedefs until they are loaded
|
|
void P_FinishLoadingLineDefs (void)
|
|
{
|
|
int i;
|
|
register line_t *ld = lines;
|
|
|
|
for (i = numlines; i--; ld++) {
|
|
ld->frontsector = ld->sidenum[0]!=-1 ? sides[ld->sidenum[0]].sector : 0;
|
|
ld->backsector = ld->sidenum[1]!=-1 ? sides[ld->sidenum[1]].sector : 0;
|
|
|
|
switch (ld->special)
|
|
{ // killough 4/11/98: handle special types
|
|
int j;
|
|
|
|
case TranslucentLine: // killough 4/11/98: translucent 2s textures
|
|
#if 0
|
|
lump = sides[*ld->sidenum].special; // translucency from sidedef
|
|
if (!ld->tag) // if tag==0,
|
|
ld->tranlump = lump; // affect this linedef only
|
|
else
|
|
for (j=0;j<numlines;j++) // if tag!=0,
|
|
if (lines[j].tag == ld->tag) // affect all matching linedefs
|
|
lines[j].tranlump = lump;
|
|
#else
|
|
// [RH] Second arg controls how opaque it is.
|
|
if (!ld->args[0])
|
|
ld->lucency = (byte)ld->args[1];
|
|
else
|
|
for (j = 0; j < numlines; j++)
|
|
if (lines[j].id == ld->args[0])
|
|
lines[j].lucency = (byte)ld->args[1];
|
|
#endif
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void P_LoadLineDefs (int lump)
|
|
{
|
|
byte *data;
|
|
int i;
|
|
line_t *ld;
|
|
|
|
numlines = W_LumpLength (lump) / sizeof(maplinedef_t);
|
|
lines = Z_Malloc (numlines*sizeof(line_t),PU_LEVEL,0);
|
|
memset (lines, 0, numlines*sizeof(line_t));
|
|
data = W_CacheLumpNum (lump,PU_STATIC);
|
|
|
|
ld = lines;
|
|
for (i=0 ; i<numlines ; i++, ld++)
|
|
{
|
|
maplinedef_t *mld = ((maplinedef_t *)data) + i;
|
|
|
|
// [RH] Translate old linedef special and flags to be
|
|
// compatible with the new format.
|
|
P_TranslateLineDef (ld, mld);
|
|
|
|
ld->v1 = &vertexes[SHORT(mld->v1)];
|
|
ld->v2 = &vertexes[SHORT(mld->v2)];
|
|
|
|
ld->sidenum[0] = SHORT(mld->sidenum[0]);
|
|
ld->sidenum[1] = SHORT(mld->sidenum[1]);
|
|
|
|
P_AdjustLine (ld);
|
|
}
|
|
|
|
Z_Free (data);
|
|
}
|
|
|
|
// [RH] Same as P_LoadLineDefs() except it uses Hexen-style LineDefs.
|
|
void P_LoadLineDefs2 (int lump)
|
|
{
|
|
byte* data;
|
|
int i;
|
|
maplinedef2_t* mld;
|
|
line_t* ld;
|
|
|
|
numlines = W_LumpLength (lump) / sizeof(maplinedef2_t);
|
|
lines = Z_Malloc (numlines*sizeof(line_t), PU_LEVEL,0 );
|
|
memset (lines, 0, numlines*sizeof(line_t));
|
|
data = W_CacheLumpNum (lump, PU_STATIC);
|
|
|
|
mld = (maplinedef2_t *)data;
|
|
ld = lines;
|
|
for (i = 0; i < numlines; i++, mld++, ld++)
|
|
{
|
|
int j;
|
|
|
|
for (j = 0; j < 5; j++)
|
|
ld->args[j] = mld->args[j];
|
|
|
|
ld->flags = SHORT(mld->flags);
|
|
ld->special = mld->special;
|
|
|
|
ld->v1 = &vertexes[SHORT(mld->v1)];
|
|
ld->v2 = &vertexes[SHORT(mld->v2)];
|
|
|
|
ld->sidenum[0] = SHORT(mld->sidenum[0]);
|
|
ld->sidenum[1] = SHORT(mld->sidenum[1]);
|
|
|
|
P_AdjustLine (ld);
|
|
}
|
|
|
|
Z_Free (data);
|
|
}
|
|
|
|
|
|
//
|
|
// P_LoadSideDefs
|
|
//
|
|
// killough 4/4/98: split into two functions
|
|
void P_LoadSideDefs (int lump)
|
|
{
|
|
numsides = W_LumpLength (lump) / sizeof(mapsidedef_t);
|
|
sides = Z_Malloc (numsides*sizeof(side_t), PU_LEVEL, 0);
|
|
memset (sides, 0, numsides*sizeof(side_t));
|
|
}
|
|
|
|
// [RH] Figure out blends for deep water sectors
|
|
static void SetTexture (short *texture, unsigned int *blend, char *name)
|
|
{
|
|
if ((*blend = R_ColormapNumForName (name)) == 0) {
|
|
if ((*texture = R_CheckTextureNumForName (name)) == -1) {
|
|
char name2[9];
|
|
char *stop;
|
|
strncpy (name2, name, 8);
|
|
name2[8] = 0;
|
|
*blend = strtoul (name2, &stop, 16);
|
|
*texture = 0;
|
|
} else {
|
|
*blend = 0;
|
|
}
|
|
} else {
|
|
*texture = 0;
|
|
}
|
|
}
|
|
|
|
static void SetTextureNoErr (short *texture, unsigned int *color, char *name)
|
|
{
|
|
if ((*texture = R_CheckTextureNumForName (name)) == -1) {
|
|
char name2[9];
|
|
char *stop;
|
|
strncpy (name2, name, 8);
|
|
name2[8] = 0;
|
|
*color = strtoul (name2, &stop, 16);
|
|
*texture = 0;
|
|
}
|
|
}
|
|
|
|
// killough 4/4/98: delay using texture names until
|
|
// after linedefs are loaded, to allow overloading.
|
|
// killough 5/3/98: reformatted, cleaned up
|
|
|
|
void P_LoadSideDefs2 (int lump)
|
|
{
|
|
byte *data = W_CacheLumpNum(lump,PU_STATIC);
|
|
int i;
|
|
|
|
for (i=0; i<numsides; i++)
|
|
{
|
|
register mapsidedef_t *msd = (mapsidedef_t *) data + i;
|
|
register side_t *sd = sides + i;
|
|
register sector_t *sec;
|
|
|
|
sd->textureoffset = SHORT(msd->textureoffset)<<FRACBITS;
|
|
sd->rowoffset = SHORT(msd->rowoffset)<<FRACBITS;
|
|
|
|
// killough 4/4/98: allow sidedef texture names to be overloaded
|
|
// killough 4/11/98: refined to allow colormaps to work as wall
|
|
// textures if invalid as colormaps but valid as textures.
|
|
|
|
sd->sector = sec = §ors[SHORT(msd->sector)];
|
|
switch (sd->special)
|
|
{
|
|
case Transfer_Heights: // variable colormap via 242 linedef
|
|
// [RH] The colormap num we get here isn't really a colormap,
|
|
// but a packed ARGB word for blending, so we also allow
|
|
// the blend to be specified directly by the texture names
|
|
// instead of figuring something out from the colormap.
|
|
SetTexture (&sd->bottomtexture, &sec->bottommap, msd->bottomtexture);
|
|
SetTexture (&sd->midtexture, &sec->midmap, msd->midtexture);
|
|
SetTexture (&sd->toptexture, &sec->topmap, msd->toptexture);
|
|
break;
|
|
|
|
case Static_Init:
|
|
// [RH] Set sector color and fog
|
|
// upper "texture" is light color
|
|
// lower "texture" is fog color
|
|
{
|
|
unsigned int color = 0xffffff, fog = 0x000000;
|
|
|
|
SetTextureNoErr (&sd->bottomtexture, &fog, msd->bottomtexture);
|
|
SetTextureNoErr (&sd->toptexture, &color, msd->toptexture);
|
|
sd->midtexture = R_TextureNumForName (msd->midtexture);
|
|
|
|
if (fog != 0x000000 || color != 0xffffff) {
|
|
int s;
|
|
dyncolormap_t *colormap = GetSpecialLights
|
|
(RPART(color), GPART(color), BPART(color),
|
|
RPART(fog), GPART(fog), BPART(fog));
|
|
|
|
for (s = 0; s < numsectors; s++) {
|
|
if (sectors[s].tag == sd->tag)
|
|
sectors[s].colormap = colormap;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
/*
|
|
case TranslucentLine: // killough 4/11/98: apply translucency to 2s normal texture
|
|
sd->midtexture = strncasecmp("TRANMAP", msd->midtexture, 8) ?
|
|
(sd->special = W_CheckNumForName(msd->midtexture)) < 0 ||
|
|
W_LumpLength(sd->special) != 65536 ?
|
|
sd->special=0, R_TextureNumForName(msd->midtexture) :
|
|
(sd->special++, 0) : (sd->special=0);
|
|
sd->toptexture = R_TextureNumForName(msd->toptexture);
|
|
sd->bottomtexture = R_TextureNumForName(msd->bottomtexture);
|
|
break;
|
|
*/
|
|
default: // normal cases
|
|
sd->midtexture = R_TextureNumForName(msd->midtexture);
|
|
sd->toptexture = R_TextureNumForName(msd->toptexture);
|
|
sd->bottomtexture = R_TextureNumForName(msd->bottomtexture);
|
|
break;
|
|
}
|
|
}
|
|
Z_Free (data);
|
|
}
|
|
|
|
|
|
//
|
|
// jff 10/6/98
|
|
// New code added to speed up calculation of internal blockmap
|
|
// Algorithm is order of nlines*(ncols+nrows) not nlines*ncols*nrows
|
|
//
|
|
|
|
#define blkshift 7 /* places to shift rel position for cell num */
|
|
#define blkmask ((1<<blkshift)-1)/* mask for rel position within cell */
|
|
#define blkmargin 0 /* size guardband around map used */
|
|
// jff 10/8/98 use guardband>0
|
|
// jff 10/12/98 0 ok with + 1 in rows,cols
|
|
|
|
typedef struct linelist_t // type used to list lines in each block
|
|
{
|
|
long num;
|
|
struct linelist_t *next;
|
|
} linelist_t;
|
|
|
|
//
|
|
// Subroutine to add a line number to a block list
|
|
// It simply returns if the line is already in the block
|
|
//
|
|
|
|
static void AddBlockLine
|
|
(
|
|
linelist_t **lists,
|
|
int *count,
|
|
int *done,
|
|
int blockno,
|
|
long lineno
|
|
)
|
|
{
|
|
linelist_t *l;
|
|
|
|
if (done[blockno])
|
|
return;
|
|
|
|
l = Malloc (sizeof(linelist_t));
|
|
l->num = lineno;
|
|
l->next = lists[blockno];
|
|
lists[blockno] = l;
|
|
count[blockno]++;
|
|
done[blockno] = 1;
|
|
}
|
|
|
|
//
|
|
// Actually construct the blockmap lump from the level data
|
|
//
|
|
// This finds the intersection of each linedef with the column and
|
|
// row lines at the left and bottom of each blockmap cell. It then
|
|
// adds the line to all block lists touching the intersection.
|
|
//
|
|
|
|
void P_CreateBlockMap()
|
|
{
|
|
int xorg,yorg; // blockmap origin (lower left)
|
|
int nrows,ncols; // blockmap dimensions
|
|
linelist_t **blocklists=NULL; // array of pointers to lists of lines
|
|
int *blockcount=NULL; // array of counters of line lists
|
|
int *blockdone=NULL; // array keeping track of blocks/line
|
|
int NBlocks; // number of cells = nrows*ncols
|
|
long linetotal=0; // total length of all blocklists
|
|
int i,j;
|
|
int map_minx=MAXINT; // init for map limits search
|
|
int map_miny=MAXINT;
|
|
int map_maxx=MININT;
|
|
int map_maxy=MININT;
|
|
|
|
// scan for map limits, which the blockmap must enclose
|
|
|
|
for (i = 0; i < numvertexes; i++)
|
|
{
|
|
fixed_t t;
|
|
|
|
if ((t=vertexes[i].x) < map_minx)
|
|
map_minx = t;
|
|
else if (t > map_maxx)
|
|
map_maxx = t;
|
|
if ((t=vertexes[i].y) < map_miny)
|
|
map_miny = t;
|
|
else if (t > map_maxy)
|
|
map_maxy = t;
|
|
}
|
|
map_minx >>= FRACBITS; // work in map coords, not fixed_t
|
|
map_maxx >>= FRACBITS;
|
|
map_miny >>= FRACBITS;
|
|
map_maxy >>= FRACBITS;
|
|
|
|
// set up blockmap area to enclose level plus margin
|
|
|
|
xorg = map_minx-blkmargin;
|
|
yorg = map_miny-blkmargin;
|
|
ncols = (map_maxx+blkmargin-xorg+1+blkmask)>>blkshift; //jff 10/12/98
|
|
nrows = (map_maxy+blkmargin-yorg+1+blkmask)>>blkshift; //+1 needed for
|
|
NBlocks = ncols*nrows; //map exactly 1 cell
|
|
|
|
// create the array of pointers on NBlocks to blocklists
|
|
// also create an array of linelist counts on NBlocks
|
|
// finally make an array in which we can mark blocks done per line
|
|
|
|
blocklists = Malloc (NBlocks*sizeof(linelist_t *));
|
|
memset (blocklists, 0, NBlocks*sizeof(linelist_t *));
|
|
blockcount = Malloc (NBlocks*sizeof(int));
|
|
memset (blockcount, 0, NBlocks*sizeof(int));
|
|
blockdone = Malloc (NBlocks*sizeof(int));
|
|
|
|
// initialize each blocklist, and enter the trailing -1 in all blocklists
|
|
// note the linked list of lines grows backwards
|
|
|
|
for (i = 0; i < NBlocks; i++)
|
|
{
|
|
blocklists[i] = Malloc(sizeof(linelist_t));
|
|
blocklists[i]->num = -1;
|
|
blocklists[i]->next = NULL;
|
|
blockcount[i]++;
|
|
}
|
|
|
|
// For each linedef in the wad, determine all blockmap blocks it touches,
|
|
// and add the linedef number to the blocklists for those blocks
|
|
|
|
for (i = 0; i < numlines; i++)
|
|
{
|
|
int x1 = lines[i].v1->x>>FRACBITS; // lines[i] map coords
|
|
int y1 = lines[i].v1->y>>FRACBITS;
|
|
int x2 = lines[i].v2->x>>FRACBITS;
|
|
int y2 = lines[i].v2->y>>FRACBITS;
|
|
int dx = x2-x1;
|
|
int dy = y2-y1;
|
|
int vert = !dx; // lines[i] slopetype
|
|
int horiz = !dy;
|
|
int spos = (dx^dy) > 0;
|
|
int sneg = (dx^dy) < 0;
|
|
int bx,by; // block cell coords
|
|
int minx = x1>x2? x2 : x1; // extremal lines[i] coords
|
|
int maxx = x1>x2? x1 : x2;
|
|
int miny = y1>y2? y2 : y1;
|
|
int maxy = y1>y2? y1 : y2;
|
|
|
|
// no blocks done for this linedef yet
|
|
|
|
memset (blockdone, 0, NBlocks*sizeof(int));
|
|
|
|
// The line always belongs to the blocks containing its endpoints
|
|
|
|
bx = (x1-xorg) >> blkshift;
|
|
by = (y1-yorg) >> blkshift;
|
|
AddBlockLine (blocklists, blockcount, blockdone, by*ncols+bx, i);
|
|
bx = (x2-xorg) >> blkshift;
|
|
by = (y2-yorg) >> blkshift;
|
|
AddBlockLine (blocklists, blockcount, blockdone, by*ncols+bx, i);
|
|
|
|
// For each column, see where the line along its left edge, which
|
|
// it contains, intersects the Linedef i. Add i to each corresponding
|
|
// blocklist.
|
|
|
|
if (!vert) // don't interesect vertical lines with columns
|
|
{
|
|
for (j=0;j<ncols;j++)
|
|
{
|
|
// intersection of Linedef with x=xorg+(j<<blkshift)
|
|
// (y-y1)*dx = dy*(x-x1)
|
|
// y = dy*(x-x1)+y1*dx;
|
|
|
|
int x = xorg+(j<<blkshift); // (x,y) is intersection
|
|
int y = (dy*(x-x1))/dx+y1;
|
|
int yb = (y-yorg)>>blkshift; // block row number
|
|
int yp = (y-yorg)&blkmask; // y position within block
|
|
|
|
if (yb<0 || yb>nrows-1) // outside blockmap, continue
|
|
continue;
|
|
|
|
if (x<minx || x>maxx) // line doesn't touch column
|
|
continue;
|
|
|
|
// The cell that contains the intersection point is always added
|
|
|
|
AddBlockLine(blocklists,blockcount,blockdone,ncols*yb+j,i);
|
|
|
|
// if the intersection is at a corner it depends on the slope
|
|
// (and whether the line extends past the intersection) which
|
|
// blocks are hit
|
|
|
|
if (yp==0) // intersection at a corner
|
|
{
|
|
if (sneg) // \ - blocks x,y-, x-,y
|
|
{
|
|
if (yb>0 && miny<y)
|
|
AddBlockLine(blocklists, blockcount, blockdone, ncols*(yb-1)+j, i);
|
|
if (j>0 && minx<x)
|
|
AddBlockLine(blocklists, blockcount, blockdone, ncols*yb+j-1, i);
|
|
}
|
|
else if (spos) // / - block x-,y-
|
|
{
|
|
if (yb>0 && j>0 && minx<x)
|
|
AddBlockLine(blocklists,blockcount,blockdone,ncols*(yb-1)+j-1,i);
|
|
}
|
|
else if (horiz) // - - block x-,y
|
|
{
|
|
if (j>0 && minx<x)
|
|
AddBlockLine(blocklists,blockcount,blockdone,ncols*yb+j-1,i);
|
|
}
|
|
}
|
|
else if (j>0 && minx<x) // else not at corner: x-,y
|
|
AddBlockLine(blocklists,blockcount,blockdone,ncols*yb+j-1,i);
|
|
}
|
|
}
|
|
|
|
// For each row, see where the line along its bottom edge, which
|
|
// it contains, intersects the Linedef i. Add i to all the corresponding
|
|
// blocklists.
|
|
|
|
if (!horiz)
|
|
{
|
|
for (j=0;j<nrows;j++)
|
|
{
|
|
// intersection of Linedef with y=yorg+(j<<blkshift)
|
|
// (x,y) on Linedef i satisfies: (y-y1)*dx = dy*(x-x1)
|
|
// x = dx*(y-y1)/dy+x1;
|
|
|
|
int y = yorg+(j<<blkshift); // (x,y) is intersection
|
|
int x = (dx*(y-y1))/dy+x1;
|
|
int xb = (x-xorg)>>blkshift; // block column number
|
|
int xp = (x-xorg)&blkmask; // x position within block
|
|
|
|
if (xb<0 || xb>ncols-1) // outside blockmap, continue
|
|
continue;
|
|
|
|
if (y<miny || y>maxy) // line doesn't touch row
|
|
continue;
|
|
|
|
// The cell that contains the intersection point is always added
|
|
|
|
AddBlockLine (blocklists, blockcount, blockdone, ncols*j+xb, i);
|
|
|
|
// if the intersection is at a corner it depends on the slope
|
|
// (and whether the line extends past the intersection) which
|
|
// blocks are hit
|
|
|
|
if (xp==0) // intersection at a corner
|
|
{
|
|
if (sneg) // \ - blocks x,y-, x-,y
|
|
{
|
|
if (j>0 && miny<y)
|
|
AddBlockLine (blocklists, blockcount, blockdone, ncols*(j-1)+xb, i);
|
|
if (xb>0 && minx<x)
|
|
AddBlockLine (blocklists, blockcount, blockdone, ncols*j+xb-1, i);
|
|
}
|
|
else if (vert) // | - block x,y-
|
|
{
|
|
if (j>0 && miny<y)
|
|
AddBlockLine (blocklists, blockcount, blockdone, ncols*(j-1)+xb, i);
|
|
}
|
|
else if (spos) // / - block x-,y-
|
|
{
|
|
if (xb>0 && j>0 && miny<y)
|
|
AddBlockLine (blocklists, blockcount, blockdone, ncols*(j-1)+xb-1, i);
|
|
}
|
|
}
|
|
else if (j>0 && miny<y) // else not on a corner: x,y-
|
|
AddBlockLine (blocklists, blockcount, blockdone, ncols*(j-1)+xb, i);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Add initial 0 to all blocklists
|
|
// count the total number of lines (and 0's and -1's)
|
|
|
|
memset (blockdone, 0, NBlocks*sizeof(int));
|
|
for (i = 0, linetotal = 0; i < NBlocks; i++)
|
|
{
|
|
AddBlockLine (blocklists, blockcount, blockdone, i, 0);
|
|
linetotal += blockcount[i];
|
|
}
|
|
|
|
// Create the blockmap lump
|
|
|
|
blockmaplump = Z_Malloc(sizeof(*blockmaplump) * (4+NBlocks+linetotal),
|
|
PU_LEVEL, 0);
|
|
// blockmap header
|
|
|
|
blockmaplump[0] = bmaporgx = xorg << FRACBITS;
|
|
blockmaplump[1] = bmaporgy = yorg << FRACBITS;
|
|
blockmaplump[2] = bmapwidth = ncols;
|
|
blockmaplump[3] = bmapheight = nrows;
|
|
|
|
// offsets to lists and block lists
|
|
|
|
for (i = 0; i < NBlocks; i++)
|
|
{
|
|
linelist_t *bl = blocklists[i];
|
|
long offs = blockmaplump[4+i] = // set offset to block's list
|
|
(i? blockmaplump[4+i-1] : 4+NBlocks) + (i? blockcount[i-1] : 0);
|
|
|
|
// add the lines in each block's list to the blockmaplump
|
|
// delete each list node as we go
|
|
|
|
while (bl)
|
|
{
|
|
linelist_t *tmp = bl->next;
|
|
blockmaplump[offs++] = bl->num;
|
|
free(bl);
|
|
bl = tmp;
|
|
}
|
|
}
|
|
|
|
// free all temporary storage
|
|
|
|
free (blocklists);
|
|
free (blockcount);
|
|
free (blockdone);
|
|
}
|
|
|
|
// jff 10/6/98
|
|
// End new code added to speed up calculation of internal blockmap
|
|
|
|
//
|
|
// P_LoadBlockMap
|
|
//
|
|
// [RH] Took a look at BOOM's version and made some changes.
|
|
//
|
|
void P_LoadBlockMap (int lump)
|
|
{
|
|
int count;
|
|
|
|
if (M_CheckParm("-blockmap") || (count = W_LumpLength(lump)/2) >= 0x10000)
|
|
P_CreateBlockMap();
|
|
else {
|
|
short *wadblockmaplump = W_CacheLumpNum (lump, PU_LEVEL);
|
|
int i;
|
|
blockmaplump = Z_Malloc(sizeof(*blockmaplump) * count, PU_LEVEL, 0);
|
|
|
|
// killough 3/1/98: Expand wad blockmap into larger internal one,
|
|
// by treating all offsets except -1 as unsigned and zero-extending
|
|
// them. This potentially doubles the size of blockmaps allowed,
|
|
// because Doom originally considered the offsets as always signed.
|
|
|
|
blockmaplump[0] = SHORT(wadblockmaplump[0]);
|
|
blockmaplump[1] = SHORT(wadblockmaplump[1]);
|
|
blockmaplump[2] = (long)(SHORT(wadblockmaplump[2])) & 0xffff;
|
|
blockmaplump[3] = (long)(SHORT(wadblockmaplump[3])) & 0xffff;
|
|
|
|
for (i=4 ; i<count ; i++)
|
|
{
|
|
short t = SHORT(wadblockmaplump[i]); // killough 3/1/98
|
|
blockmaplump[i] = t == -1 ? -1l : (long) t & 0xffff;
|
|
}
|
|
|
|
Z_Free (wadblockmaplump);
|
|
}
|
|
|
|
bmaporgx = blockmaplump[0]<<FRACBITS;
|
|
bmaporgy = blockmaplump[1]<<FRACBITS;
|
|
bmapwidth = blockmaplump[2];
|
|
bmapheight = blockmaplump[3];
|
|
|
|
// clear out mobj chains
|
|
count = sizeof(*blocklinks) * bmapwidth*bmapheight;
|
|
blocklinks = Z_Malloc (count, PU_LEVEL, 0);
|
|
memset (blocklinks, 0, count);
|
|
blockmap = blockmaplump+4;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// P_GroupLines
|
|
// Builds sector line lists and subsector sector numbers.
|
|
// Finds block bounding boxes for sectors.
|
|
//
|
|
void P_GroupLines (void)
|
|
{
|
|
line_t** linebuffer;
|
|
int i;
|
|
int j;
|
|
int total;
|
|
line_t* li;
|
|
sector_t* sector;
|
|
fixed_t bbox[4];
|
|
int block;
|
|
|
|
// look up sector number for each subsector
|
|
for (i = 0; i < numsubsectors; i++)
|
|
subsectors[i].sector = segs[subsectors[i].firstline].sidedef->sector;
|
|
|
|
// count number of lines in each sector
|
|
li = lines;
|
|
total = 0;
|
|
for (i = 0; i < numlines; i++, li++)
|
|
{
|
|
total++;
|
|
li->frontsector->linecount++;
|
|
|
|
if (li->backsector && li->backsector != li->frontsector)
|
|
{
|
|
li->backsector->linecount++;
|
|
total++;
|
|
}
|
|
}
|
|
|
|
// build line tables for each sector
|
|
linebuffer = Z_Malloc (total*4, PU_LEVEL, 0);
|
|
sector = sectors;
|
|
for (i=0 ; i<numsectors ; i++, sector++)
|
|
{
|
|
M_ClearBox (bbox);
|
|
sector->lines = linebuffer;
|
|
li = lines;
|
|
for (j=0 ; j<numlines ; j++, li++)
|
|
{
|
|
if (li->frontsector == sector || li->backsector == sector)
|
|
{
|
|
*linebuffer++ = li;
|
|
M_AddToBox (bbox, li->v1->x, li->v1->y);
|
|
M_AddToBox (bbox, li->v2->x, li->v2->y);
|
|
}
|
|
}
|
|
if (linebuffer - sector->lines != sector->linecount)
|
|
I_Error ("P_GroupLines: miscounted");
|
|
|
|
// set the degenmobj_t to the middle of the bounding box
|
|
sector->soundorg.x = (bbox[BOXRIGHT]+bbox[BOXLEFT])/2;
|
|
sector->soundorg.y = (bbox[BOXTOP]+bbox[BOXBOTTOM])/2;
|
|
|
|
// adjust bounding box to map blocks
|
|
block = (bbox[BOXTOP]-bmaporgy+MAXRADIUS)>>MAPBLOCKSHIFT;
|
|
block = block >= bmapheight ? bmapheight-1 : block;
|
|
sector->blockbox[BOXTOP]=block;
|
|
|
|
block = (bbox[BOXBOTTOM]-bmaporgy-MAXRADIUS)>>MAPBLOCKSHIFT;
|
|
block = block < 0 ? 0 : block;
|
|
sector->blockbox[BOXBOTTOM]=block;
|
|
|
|
block = (bbox[BOXRIGHT]-bmaporgx+MAXRADIUS)>>MAPBLOCKSHIFT;
|
|
block = block >= bmapwidth ? bmapwidth-1 : block;
|
|
sector->blockbox[BOXRIGHT]=block;
|
|
|
|
block = (bbox[BOXLEFT]-bmaporgx-MAXRADIUS)>>MAPBLOCKSHIFT;
|
|
block = block < 0 ? 0 : block;
|
|
sector->blockbox[BOXLEFT]=block;
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// [RH] P_LoadBehavior
|
|
//
|
|
static int STACK_ARGS sortscripts (const void *a, const void *b)
|
|
{
|
|
return ((*(int *)a)%1000 - (*(int *)b)%1000);
|
|
}
|
|
|
|
void P_LoadBehavior (int lumpnum)
|
|
{
|
|
byte *behavior = W_CacheLumpNum (lumpnum, PU_LEVEL);
|
|
|
|
if (strncmp (behavior, "ACS", 4)) {
|
|
Z_Free (behavior);
|
|
return;
|
|
}
|
|
|
|
level.behavior = behavior;
|
|
level.scripts = (int *)(behavior + ((int *)behavior)[1]);
|
|
level.strings = &level.scripts[level.scripts[0]*3+1];
|
|
|
|
// Make sure scripts are listed in order (to make finding them quicker)
|
|
qsort (&level.scripts[1], level.scripts[0], 3*sizeof(int), sortscripts);
|
|
|
|
DPrintf ("Loaded %d scripts, %d strings\n", level.scripts[0], level.strings[0]);
|
|
}
|
|
|
|
//
|
|
// P_SetupLevel
|
|
//
|
|
extern dyncolormap_t NormalLight;
|
|
extern mobj_t *bodyquesize[];
|
|
extern polyblock_t **PolyBlockMap;
|
|
|
|
// [RH] position indicates the start spot to spawn at
|
|
void P_SetupLevel (char *lumpname, int position)
|
|
{
|
|
int i, lumpnum;
|
|
|
|
level.total_monsters = level.total_items = level.total_secrets =
|
|
level.killed_monsters = level.found_items = level.found_secrets =
|
|
wminfo.maxfrags = 0;
|
|
wminfo.partime = 180;
|
|
for (i=0 ; i<MAXPLAYERS ; i++)
|
|
{
|
|
players[i].killcount = players[i].secretcount
|
|
= players[i].itemcount = 0;
|
|
}
|
|
|
|
// Initial height of PointOfView will be set by player think.
|
|
players[consoleplayer].viewz = 1;
|
|
|
|
// Make sure all sounds are stopped before Z_FreeTags.
|
|
S_Start ();
|
|
|
|
// [RH] Clear all ThingID hash chains.
|
|
P_ClearTidHashes ();
|
|
|
|
PolyBlockMap = NULL;
|
|
|
|
#if 0 // UNUSED
|
|
if (debugfile)
|
|
{
|
|
Z_FreeTags (PU_LEVEL, MAXINT);
|
|
Z_FileDumpHeap (debugfile);
|
|
}
|
|
else
|
|
#endif
|
|
Z_FreeTags (PU_LEVEL, PU_PURGELEVEL-1);
|
|
NormalLight.next = NULL; // [RH] Z_FreeTags frees all the custom colormaps
|
|
|
|
// UNUSED W_Profile ();
|
|
P_InitThinkers ();
|
|
|
|
// find map num
|
|
lumpnum = W_GetNumForName (lumpname);
|
|
|
|
// [RH] Check if this map is Hexen-style.
|
|
// LINEDEFS and THINGS need to be handled accordingly.
|
|
// If it is, we also need to distinguish between projectile cross and hit
|
|
HasBehavior = W_CheckLumpName (lumpnum+ML_BEHAVIOR, "BEHAVIOR");
|
|
oldshootactivation = !HasBehavior;
|
|
|
|
// note: most of this ordering is important
|
|
P_LoadVertexes (lumpnum+ML_VERTEXES);
|
|
P_LoadSectors (lumpnum+ML_SECTORS);
|
|
P_LoadSideDefs (lumpnum+ML_SIDEDEFS);
|
|
if (!HasBehavior)
|
|
P_LoadLineDefs (lumpnum+ML_LINEDEFS);
|
|
else
|
|
P_LoadLineDefs2 (lumpnum+ML_LINEDEFS); // [RH] Load Hexen-style linedefs
|
|
P_LoadSideDefs2 (lumpnum+ML_SIDEDEFS);
|
|
P_FinishLoadingLineDefs ();
|
|
P_LoadBlockMap (lumpnum+ML_BLOCKMAP);
|
|
P_LoadSubsectors (lumpnum+ML_SSECTORS);
|
|
P_LoadNodes (lumpnum+ML_NODES);
|
|
P_LoadSegs (lumpnum+ML_SEGS);
|
|
|
|
rejectmatrix = W_CacheLumpNum (lumpnum+ML_REJECT, PU_LEVEL);
|
|
{
|
|
// [RH] Scan the rejectmatrix and see if it actually contains anything
|
|
int i, end = (W_LumpLength (lumpnum+ML_REJECT)-3) / 4;
|
|
for (i = 0; i < end; i++)
|
|
if (((int *)rejectmatrix)[i]) {
|
|
rejectempty = false;
|
|
break;
|
|
}
|
|
if (i >= end) {
|
|
DPrintf ("Reject matrix is empty\n");
|
|
rejectempty = true;
|
|
}
|
|
}
|
|
P_GroupLines ();
|
|
|
|
bodyqueslot = 0;
|
|
// phares 8/10/98: Clear body queue so the corpses from previous games are
|
|
// not assumed to be from this one. The mobj_t's belonging to these corpses
|
|
// are cleared in the normal freeing of zoned memory between maps, so all
|
|
// we have to do here is clear the pointers to them.
|
|
|
|
if (bodyque)
|
|
for (i = 0; i < BODYQUESIZE; i++)
|
|
bodyque[i] = 0;
|
|
|
|
po_NumPolyobjs = 0;
|
|
|
|
if (!deathmatchstarts) {
|
|
MaxDeathmatchStarts = 10; // [RH] Default. Increased as needed.
|
|
deathmatchstarts = Malloc (MaxDeathmatchStarts * sizeof(mapthing2_t));
|
|
}
|
|
deathmatch_p = deathmatchstarts;
|
|
|
|
if (!HasBehavior)
|
|
P_LoadThings (lumpnum+ML_THINGS);
|
|
else
|
|
P_LoadThings2 (lumpnum+ML_THINGS, position); // [RH] Load Hexen-style things
|
|
|
|
if (!HasBehavior)
|
|
P_TranslateTeleportThings (); // [RH] Assign teleport destination TIDs
|
|
|
|
PO_Init (); // Initialize the polyobjs
|
|
|
|
// [RH] Load in the BEHAVIOR lump
|
|
level.behavior = NULL;
|
|
level.scripts = level.strings = NULL;
|
|
P_ClearScripts ();
|
|
if (HasBehavior)
|
|
P_LoadBehavior (lumpnum+ML_BEHAVIOR);
|
|
|
|
// if deathmatch, randomly spawn the active players
|
|
if (deathmatch->value)
|
|
{
|
|
for (i=0 ; i<MAXPLAYERS ; i++)
|
|
if (playeringame[i])
|
|
{
|
|
players[i].mo = NULL;
|
|
G_DeathMatchSpawnPlayer (i);
|
|
}
|
|
|
|
}
|
|
|
|
// killough 3/26/98: Spawn icon landings:
|
|
if (gamemode == commercial)
|
|
P_SpawnBrainTargets();
|
|
|
|
// clear special respawning que
|
|
iquehead = iquetail = 0;
|
|
|
|
// set up world state
|
|
P_SpawnSpecials ();
|
|
|
|
// build subsector connect matrix
|
|
// UNUSED P_ConnectSubsectors ();
|
|
|
|
// preload graphics
|
|
if (precache)
|
|
R_PrecacheLevel ();
|
|
|
|
//Printf ("free memory: 0x%x\n", Z_FreeMemory());
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// P_Init
|
|
//
|
|
extern void SplashFactorCallback (cvar_t *);
|
|
extern cvar_t *splashfactor;
|
|
|
|
void P_Init (void)
|
|
{
|
|
// [RH] Set callback for splashfactor cvar.
|
|
splashfactor->u.callback = SplashFactorCallback;
|
|
SplashFactorCallback (splashfactor);
|
|
|
|
P_InitEffects (); // [RH]
|
|
P_InitSwitchList ();
|
|
P_InitPicAnims ();
|
|
R_InitSprites (sprnames);
|
|
}
|
|
|
|
|
|
|