The Return to Castle Wolfenstein Multiplayer sources as originally released under the GPL license on August 12, 2010.

This commit is contained in:
Travis Bradshaw
2012-01-31 14:59:39 -06:00
commit 937b209a3c
520 changed files with 424914 additions and 0 deletions

838
src/bspc/aas_map.c Normal file
View File

@@ -0,0 +1,838 @@
/*
===========================================================================
Return to Castle Wolfenstein multiplayer GPL Source Code
Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
This file is part of the Return to Castle Wolfenstein multiplayer GPL Source Code (“RTCW MP Source Code”).
RTCW MP Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
RTCW MP Source Code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with RTCW MP Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the RTCW MP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW MP Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
//===========================================================================
//
// Name: aas_map.c
// Function:
// Programmer: Mr Elusive (MrElusive@demigod.demon.nl)
// Last update: 1997-12-03
// Tab Size: 3
//===========================================================================
#include "qbsp.h"
#include "l_mem.h"
#include "..\botlib\aasfile.h" //aas_bbox_t
#include "aas_store.h" //AAS_MAX_BBOXES
#include "aas_cfg.h"
#include "..\game\surfaceflags.h"
#define SPAWNFLAG_NOT_EASY 0x00000100
#define SPAWNFLAG_NOT_MEDIUM 0x00000200
#define SPAWNFLAG_NOT_HARD 0x00000400
#define SPAWNFLAG_NOT_DEATHMATCH 0x00000800
#define SPAWNFLAG_NOT_COOP 0x00001000
#define STATE_TOP 0
#define STATE_BOTTOM 1
#define STATE_UP 2
#define STATE_DOWN 3
#define DOOR_START_OPEN 1
#define DOOR_REVERSE 2
#define DOOR_CRUSHER 4
#define DOOR_NOMONSTER 8
#define DOOR_TOGGLE 32
#define DOOR_X_AXIS 64
#define DOOR_Y_AXIS 128
#define BBOX_NORMAL_EPSILON 0.0001
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
vec_t BoxOriginDistanceFromPlane( vec3_t normal, vec3_t mins, vec3_t maxs, int side ) {
vec3_t v1, v2;
int i;
if ( side ) {
for ( i = 0; i < 3; i++ )
{
if ( normal[i] > BBOX_NORMAL_EPSILON ) {
v1[i] = maxs[i];
} else if ( normal[i] < -BBOX_NORMAL_EPSILON ) {
v1[i] = mins[i];
} else { v1[i] = 0;}
} //end for
} //end if
else
{
for ( i = 0; i < 3; i++ )
{
if ( normal[i] > BBOX_NORMAL_EPSILON ) {
v1[i] = mins[i];
} else if ( normal[i] < -BBOX_NORMAL_EPSILON ) {
v1[i] = maxs[i];
} else { v1[i] = 0;}
} //end for
} //end else
VectorCopy( normal, v2 );
VectorInverse( v2 );
return DotProduct( v1, v2 );
} //end of the function BoxOriginDistanceFromPlane
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
vec_t CapsuleOriginDistanceFromPlane( vec3_t normal, vec3_t mins, vec3_t maxs ) {
float offset_up, offset_down, width, radius;
width = maxs[0] - mins[0];
// if the box is less high then it is wide
if ( maxs[2] - mins[2] < width ) {
width = maxs[2] - mins[2];
}
radius = width * 0.5;
// offset to upper and lower sphere
offset_up = maxs[2] - radius;
offset_down = -mins[2] - radius;
// if normal points upward
if ( normal[2] > 0 ) {
// touches lower sphere first
return normal[2] * offset_down + radius;
} else {
// touched upper sphere first
return -normal[2] * offset_up + radius;
}
}
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void AAS_ExpandMapBrush( mapbrush_t *brush, vec3_t mins, vec3_t maxs ) {
int sn;
float dist;
side_t *s;
plane_t *plane;
for ( sn = 0; sn < brush->numsides; sn++ )
{
s = brush->original_sides + sn;
plane = &mapplanes[s->planenum];
dist = plane->dist;
if ( capsule_collision ) {
dist += CapsuleOriginDistanceFromPlane( plane->normal, mins, maxs );
} else {
dist += BoxOriginDistanceFromPlane( plane->normal, mins, maxs, 0 );
}
s->planenum = FindFloatPlane( plane->normal, dist );
//the side isn't a bevel after expanding
s->flags &= ~SFL_BEVEL;
//don't skip the surface
s->surf &= ~SURF_SKIP;
//make sure the texinfo is not TEXINFO_NODE
//when player clip contents brushes are read from the bsp tree
//they have the texinfo field set to TEXINFO_NODE
//s->texinfo = 0;
} //end for
} //end of the function AAS_ExpandMapBrush
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void AAS_SetTexinfo( mapbrush_t *brush ) {
int n;
side_t *side;
if ( brush->contents & ( CONTENTS_LADDER
| CONTENTS_AREAPORTAL
| CONTENTS_CLUSTERPORTAL
| CONTENTS_TELEPORTER
| CONTENTS_JUMPPAD
| CONTENTS_DONOTENTER
| CONTENTS_DONOTENTER_LARGE
| CONTENTS_WATER
| CONTENTS_LAVA
| CONTENTS_SLIME
| CONTENTS_WINDOW
| CONTENTS_PLAYERCLIP ) ) {
//we just set texinfo to 0 because these brush sides MUST be used as
//bsp splitters textured or not textured
for ( n = 0; n < brush->numsides; n++ )
{
side = brush->original_sides + n;
//side->flags |= SFL_TEXTURED|SFL_VISIBLE;
side->texinfo = 0;
} //end for
} //end if
else
{
//only use brush sides as splitters if they are textured
//texinfo of non-textured sides will be set to TEXINFO_NODE
for ( n = 0; n < brush->numsides; n++ )
{
side = brush->original_sides + n;
//don't use side as splitter (set texinfo to TEXINFO_NODE) if not textured
if ( side->flags & ( SFL_TEXTURED | SFL_BEVEL ) ) {
side->texinfo = 0;
} else { side->texinfo = TEXINFO_NODE;}
} //end for
} //end else
} //end of the function AAS_SetTexinfo
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void FreeBrushWindings( mapbrush_t *brush ) {
int n;
side_t *side;
//
for ( n = 0; n < brush->numsides; n++ )
{
side = brush->original_sides + n;
//
if ( side->winding ) {
FreeWinding( side->winding );
}
} //end for
} //end of the function FreeBrushWindings
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void AAS_AddMapBrushSide( mapbrush_t *brush, int planenum ) {
side_t *side;
//
if ( nummapbrushsides >= MAX_MAPFILE_BRUSHSIDES ) {
Error( "MAX_MAPFILE_BRUSHSIDES" );
}
//
side = brush->original_sides + brush->numsides;
side->original = NULL;
side->winding = NULL;
side->contents = brush->contents;
side->flags &= ~( SFL_BEVEL | SFL_VISIBLE );
side->surf = 0;
side->planenum = planenum;
side->texinfo = 0;
//
nummapbrushsides++;
brush->numsides++;
} //end of the function AAS_AddMapBrushSide
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void AAS_FixMapBrush( mapbrush_t *brush ) {
int i, j, planenum;
float dist;
winding_t *w;
plane_t *plane, *plane1, *plane2;
side_t *side;
vec3_t normal;
//calculate the brush bounds
ClearBounds( brush->mins, brush->maxs );
for ( i = 0; i < brush->numsides; i++ )
{
plane = &mapplanes[brush->original_sides[i].planenum];
w = BaseWindingForPlane( plane->normal, plane->dist );
for ( j = 0; j < brush->numsides && w; j++ )
{
if ( i == j ) {
continue;
}
//there are no brush bevels marked but who cares :)
if ( brush->original_sides[j].flags & SFL_BEVEL ) {
continue;
}
plane = &mapplanes[brush->original_sides[j].planenum ^ 1];
ChopWindingInPlace( &w, plane->normal, plane->dist, 0 ); //CLIP_EPSILON);
} //end for
side = &brush->original_sides[i];
side->winding = w;
if ( w ) {
for ( j = 0; j < w->numpoints; j++ )
{
AddPointToBounds( w->p[j], brush->mins, brush->maxs );
} //end for
} //end if
} //end for
//
for ( i = 0; i < brush->numsides; i++ )
{
for ( j = 0; j < brush->numsides; j++ )
{
if ( i == j ) {
continue;
}
plane1 = &mapplanes[brush->original_sides[i].planenum];
plane2 = &mapplanes[brush->original_sides[j].planenum];
if ( WindingsNonConvex( brush->original_sides[i].winding,
brush->original_sides[j].winding,
plane1->normal, plane2->normal,
plane1->dist, plane2->dist ) ) {
Log_Print( "non convex brush" );
} //end if
} //end for
} //end for
//NOW close the fucking brush!!
for ( i = 0; i < 3; i++ )
{
if ( brush->mins[i] < -MAX_MAP_BOUNDS ) {
VectorClear( normal );
normal[i] = -1;
dist = MAX_MAP_BOUNDS - 10;
planenum = FindFloatPlane( normal, dist );
//
Log_Print( "mins out of range: added extra brush side\n" );
AAS_AddMapBrushSide( brush, planenum );
} //end if
if ( brush->maxs[i] > MAX_MAP_BOUNDS ) {
VectorClear( normal );
normal[i] = 1;
dist = MAX_MAP_BOUNDS - 10;
planenum = FindFloatPlane( normal, dist );
//
Log_Print( "maxs out of range: added extra brush side\n" );
AAS_AddMapBrushSide( brush, planenum );
} //end if
if ( brush->mins[i] > MAX_MAP_BOUNDS || brush->maxs[i] < -MAX_MAP_BOUNDS ) {
Log_Print( "entity %i, brush %i: no visible sides on brush\n", brush->entitynum, brush->brushnum );
} //end if
} //end for
//free all the windings
FreeBrushWindings( brush );
} //end of the function AAS_FixMapBrush
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
qboolean AAS_MakeBrushWindings( mapbrush_t *ob ) {
int i, j;
winding_t *w;
side_t *side;
plane_t *plane, *plane1, *plane2;
ClearBounds( ob->mins, ob->maxs );
for ( i = 0; i < ob->numsides; i++ )
{
plane = &mapplanes[ob->original_sides[i].planenum];
w = BaseWindingForPlane( plane->normal, plane->dist );
for ( j = 0; j < ob->numsides && w; j++ )
{
if ( i == j ) {
continue;
}
if ( ob->original_sides[j].flags & SFL_BEVEL ) {
continue;
}
plane = &mapplanes[ob->original_sides[j].planenum ^ 1];
ChopWindingInPlace( &w, plane->normal, plane->dist, 0 ); //CLIP_EPSILON);
}
side = &ob->original_sides[i];
side->winding = w;
if ( w ) {
side->flags |= SFL_VISIBLE;
for ( j = 0; j < w->numpoints; j++ )
AddPointToBounds( w->p[j], ob->mins, ob->maxs );
}
}
//check if the brush is convex
for ( i = 0; i < ob->numsides; i++ )
{
for ( j = 0; j < ob->numsides; j++ )
{
if ( i == j ) {
continue;
}
plane1 = &mapplanes[ob->original_sides[i].planenum];
plane2 = &mapplanes[ob->original_sides[j].planenum];
if ( WindingsNonConvex( ob->original_sides[i].winding,
ob->original_sides[j].winding,
plane1->normal, plane2->normal,
plane1->dist, plane2->dist ) ) {
Log_Print( "non convex brush" );
} //end if
} //end for
} //end for
//check for out of bound brushes
for ( i = 0; i < 3; i++ )
{
//IDBUG: all the indexes into the mins and maxs were zero (not using i)
if ( ob->mins[i] < -MAX_MAP_BOUNDS || ob->maxs[i] > MAX_MAP_BOUNDS ) {
Log_Print( "entity %i, brush %i: bounds out of range\n", ob->entitynum, ob->brushnum );
Log_Print( "ob->mins[%d] = %f, ob->maxs[%d] = %f\n", i, ob->mins[i], i, ob->maxs[i] );
ob->numsides = 0; //remove the brush
break;
} //end if
if ( ob->mins[i] > MAX_MAP_BOUNDS || ob->maxs[i] < -MAX_MAP_BOUNDS ) {
Log_Print( "entity %i, brush %i: no visible sides on brush\n", ob->entitynum, ob->brushnum );
Log_Print( "ob->mins[%d] = %f, ob->maxs[%d] = %f\n", i, ob->mins[i], i, ob->maxs[i] );
ob->numsides = 0; //remove the brush
break;
} //end if
} //end for
return true;
} //end of the function AAS_MakeBrushWindings
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
mapbrush_t *AAS_CopyMapBrush( mapbrush_t *brush, entity_t *mapent ) {
int n;
mapbrush_t *newbrush;
side_t *side, *newside;
if ( nummapbrushes >= MAX_MAPFILE_BRUSHES ) {
Error( "MAX_MAPFILE_BRUSHES" );
}
newbrush = &mapbrushes[nummapbrushes];
newbrush->original_sides = &brushsides[nummapbrushsides];
newbrush->entitynum = brush->entitynum;
newbrush->brushnum = nummapbrushes - mapent->firstbrush;
newbrush->numsides = brush->numsides;
newbrush->contents = brush->contents;
//copy the sides
for ( n = 0; n < brush->numsides; n++ )
{
if ( nummapbrushsides >= MAX_MAPFILE_BRUSHSIDES ) {
Error( "MAX_MAPFILE_BRUSHSIDES" );
}
side = brush->original_sides + n;
newside = newbrush->original_sides + n;
newside->original = NULL;
newside->winding = NULL;
newside->contents = side->contents;
newside->flags = side->flags;
newside->surf = side->surf;
newside->planenum = side->planenum;
newside->texinfo = side->texinfo;
nummapbrushsides++;
} //end for
//
nummapbrushes++;
mapent->numbrushes++;
return newbrush;
} //end of the function AAS_CopyMapBrush
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
int AAS_AlwaysTriggered( char *targetname ) {
int i;
if ( !strlen( targetname ) ) {
return false;
}
//
for ( i = 0; i < num_entities; i++ )
{
//if the entity will activate the given targetname
if ( !strcmp( targetname, ValueForKey( &entities[i], "target" ) ) ) {
//if this activator is present in deathmatch
if ( !( atoi( ValueForKey( &entities[i], "spawnflags" ) ) & SPAWNFLAG_NOT_DEATHMATCH ) ) {
//if it is a trigger_always entity
if ( !strcmp( "trigger_always", ValueForKey( &entities[i], "classname" ) ) ) {
return true;
} //end if
//check for possible trigger_always entities activating this entity
if ( AAS_AlwaysTriggered( ValueForKey( &entities[i], "targetname" ) ) ) {
return true;
} //end if
} //end if
} //end if
} //end for
return false;
} //end of the function AAS_AlwaysTriggered
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
int AAS_ValidEntity( entity_t *mapent ) {
int i;
char target[1024];
//all world brushes are used for AAS
if ( mapent == &entities[0] ) {
return true;
} //end if
//some of the func_wall brushes are also used for AAS
else if ( !strcmp( "func_wall", ValueForKey( mapent, "classname" ) ) ) {
//Log_Print("found func_wall entity %d\n", mapent - entities);
//if the func wall is used in deathmatch
//if (!(atoi(ValueForKey(mapent, "spawnflags")) & SPAWNFLAG_NOT_DEATHMATCH))
{
//Log_Print("func_wall USED in deathmatch mode %d\n", atoi(ValueForKey(mapent, "spawnflags")));
return true;
} //end if
} //end else if
else if ( !strcmp( "func_door_rotating", ValueForKey( mapent, "classname" ) ) ||
!strcmp( "func_door", ValueForKey( mapent, "classname" ) ) ||
!strcmp( "func_invisible_user", ValueForKey( mapent, "classname" ) ) ) {
//if the func_door_rotating is present in deathmatch
//if (!(atoi(ValueForKey(mapent, "spawnflags")) & SPAWNFLAG_NOT_DEATHMATCH))
{
//if the func_door_rotating is always activated in deathmatch
if ( AAS_AlwaysTriggered( ValueForKey( mapent, "targetname" ) ) ) {
//Log_Print("found func_door_rotating in deathmatch\ntargetname %s\n", ValueForKey(mapent, "targetname"));
return true;
} //end if
} //end if
} //end else if
else if ( !strcmp( "trigger_hurt", ValueForKey( mapent, "classname" ) ) ) {
// RF, spawnflag & 1 is for delayed spawn, so ignore it
if ( atoi( ValueForKey( mapent, "spawnflags" ) ) & 1 ) {
return false;
}
//"dmg" is the damage, for instance: "dmg" "666"
return true;
} //end else if
else if ( !strcmp( "trigger_push", ValueForKey( mapent, "classname" ) ) ) {
return true;
} //end else if
else if ( !strcmp( "trigger_multiple", ValueForKey( mapent, "classname" ) ) ) {
//find out if the trigger_multiple is pointing to a target_teleporter
strcpy( target, ValueForKey( mapent, "target" ) );
for ( i = 0; i < num_entities; i++ )
{
//if the entity will activate the given targetname
if ( !strcmp( target, ValueForKey( &entities[i], "targetname" ) ) ) {
if ( !strcmp( "target_teleporter", ValueForKey( &entities[i], "classname" ) ) ) {
return true;
} //end if
} //end if
} //end for
} //end else if
else if ( !strcmp( "trigger_teleport", ValueForKey( mapent, "classname" ) ) ) {
return true;
} //end else if
else if ( !strcmp( "func_tramcar", ValueForKey( mapent, "classname" ) ) ) {
return true;
} //end else if
else if ( !strcmp( "func_invisible_user", ValueForKey( mapent, "classname" ) ) ) {
return true;
}
/*
else if (!strcmp("func_static", ValueForKey(mapent, "classname")))
{
//FIXME: easy/medium/hard/deathmatch specific?
return true;
} //end else if
*/
return false;
} //end of the function AAS_ValidEntity
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
int AAS_TransformPlane( int planenum, vec3_t origin, vec3_t angles ) {
float newdist, matrix[3][3];
vec3_t normal;
//rotate the node plane
VectorCopy( mapplanes[planenum].normal, normal );
CreateRotationMatrix( angles, matrix );
RotatePoint( normal, matrix );
newdist = mapplanes[planenum].dist + DotProduct( normal, origin );
return FindFloatPlane( normal, newdist );
} //end of the function AAS_TransformPlane
//===========================================================================
// this function sets the func_rotating_door in it's final position
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void AAS_PositionFuncRotatingBrush( entity_t *mapent, mapbrush_t *brush ) {
int spawnflags, i;
float distance;
vec3_t movedir, angles, pos1, pos2;
side_t *s;
spawnflags = FloatForKey( mapent, "spawnflags" );
VectorClear( movedir );
if ( spawnflags & DOOR_X_AXIS ) {
movedir[2] = 1.0; //roll
} else if ( spawnflags & DOOR_Y_AXIS ) {
movedir[0] = 1.0; //pitch
} else { // Z_AXIS
movedir[1] = 1.0; //yaw
}
// check for reverse rotation
if ( spawnflags & DOOR_REVERSE ) {
VectorInverse( movedir );
}
distance = FloatForKey( mapent, "distance" );
if ( !distance ) {
distance = 90;
}
GetVectorForKey( mapent, "angles", angles );
VectorCopy( angles, pos1 );
VectorMA( angles, -distance, movedir, pos2 );
// if it starts open, switch the positions
if ( spawnflags & DOOR_START_OPEN ) {
VectorCopy( pos2, angles );
VectorCopy( pos1, pos2 );
VectorCopy( angles, pos1 );
VectorInverse( movedir );
} //end if
//
for ( i = 0; i < brush->numsides; i++ )
{
s = &brush->original_sides[i];
s->planenum = AAS_TransformPlane( s->planenum, mapent->origin, pos2 );
} //end for
//
FreeBrushWindings( brush );
AAS_MakeBrushWindings( brush );
AddBrushBevels( brush );
FreeBrushWindings( brush );
} //end of the function AAS_PositionFuncRotatingBrush
//===========================================================================
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void AAS_PositionBrush( entity_t *mapent, mapbrush_t *brush ) {
side_t *s;
float newdist;
int i;
char *model;
if ( !strcmp( ValueForKey( mapent, "classname" ), "func_door_rotating" ) ) {
AAS_PositionFuncRotatingBrush( mapent, brush );
} //end if
else
{
if ( mapent->origin[0] || mapent->origin[1] || mapent->origin[2] ) {
for ( i = 0; i < brush->numsides; i++ )
{
s = &brush->original_sides[i];
newdist = mapplanes[s->planenum].dist +
DotProduct( mapplanes[s->planenum].normal, mapent->origin );
s->planenum = FindFloatPlane( mapplanes[s->planenum].normal, newdist );
} //end for
} //end if
//if it's a trigger hurt
if ( !strcmp( "trigger_hurt", ValueForKey( mapent, "classname" ) ) ) {
//set the lava contents
brush->contents |= CONTENTS_LAVA;
//Log_Print("found trigger_hurt brush\n");
} //end if
//
else if ( !strcmp( "trigger_push", ValueForKey( mapent, "classname" ) ) ) {
//set the jumppad contents
brush->contents = CONTENTS_JUMPPAD;
//Log_Print("found trigger_push brush\n");
} //end if
//
else if ( !strcmp( "trigger_multiple", ValueForKey( mapent, "classname" ) ) ) {
//set teleporter contents
brush->contents = CONTENTS_TELEPORTER;
//Log_Print("found trigger_multiple teleporter brush\n");
} //end if
//
else if ( !strcmp( "trigger_teleport", ValueForKey( mapent, "classname" ) ) ) {
//set teleporter contents
brush->contents = CONTENTS_TELEPORTER;
//Log_Print("found trigger_teleport teleporter brush\n");
} //end if
else if ( !strcmp( "func_door", ValueForKey( mapent, "classname" ) ) ) {
//set mover contents
brush->contents = CONTENTS_MOVER;
//get the model number
model = ValueForKey( mapent, "model" );
brush->modelnum = atoi( model + 1 );
} //end if
else if ( !strcmp( "func_invisible_user", ValueForKey( mapent, "classname" ) ) ) {
//set mover contents
brush->contents = CONTENTS_TRIGGER;
} //end if
} //end else
} //end of the function AAS_PositionBrush
//===========================================================================
// uses the global cfg_t cfg
//
// Parameter: -
// Returns: -
// Changes Globals: -
//===========================================================================
void AAS_CreateMapBrushes( mapbrush_t *brush, entity_t *mapent, int addbevels ) {
int i;
//side_t *s;
mapbrush_t *bboxbrushes[16];
//if the brushes are not from an entity used for AAS
if ( !AAS_ValidEntity( mapent ) ) {
nummapbrushsides -= brush->numsides;
brush->numsides = 0;
return;
} //end if
//
AAS_PositionBrush( mapent, brush );
//from all normal solid brushes only the textured brush sides will
//be used as bsp splitters, so set the right texinfo reference here
AAS_SetTexinfo( brush );
//remove contents detail flag, otherwise player clip contents won't be
//bsped correctly for AAS!
brush->contents &= ~CONTENTS_DETAIL;
//if the brush has contents area portal it should be the only contents
if ( brush->contents & ( CONTENTS_AREAPORTAL | CONTENTS_CLUSTERPORTAL ) ) {
brush->contents = CONTENTS_CLUSTERPORTAL;
brush->leafnum = -1;
} //end if
//window and playerclip are used for player clipping, make them solid
if ( brush->contents & ( CONTENTS_WINDOW | CONTENTS_PLAYERCLIP ) ) {
//
brush->contents &= ~( CONTENTS_WINDOW | CONTENTS_PLAYERCLIP );
brush->contents |= CONTENTS_SOLID;
brush->leafnum = -1;
} //end if
//
// Rafael TBD: no flag to support CONTENTS_BOTCLIP
/*
if (brush->contents & CONTENTS_BOTCLIP)
{
brush->contents = CONTENTS_SOLID;
brush->leafnum = -1;
} // end if
*/
//
//Log_Write("brush %d contents = ", brush->brushnum);
//PrintContents(brush->contents);
//Log_Write("\r\n");
//if not one of the following brushes then the brush is NOT used for AAS
if ( !( brush->contents & ( CONTENTS_SOLID
| CONTENTS_LADDER
| CONTENTS_CLUSTERPORTAL
| CONTENTS_DONOTENTER
| CONTENTS_DONOTENTER_LARGE
| CONTENTS_TELEPORTER
| CONTENTS_JUMPPAD
| CONTENTS_WATER
| CONTENTS_LAVA
| CONTENTS_SLIME
| CONTENTS_MOVER
) ) ) {
nummapbrushsides -= brush->numsides;
brush->numsides = 0;
return;
} //end if
//fix the map brush
//AAS_FixMapBrush(brush);
//if brush bevels should be added (for real map brushes, not bsp map brushes)
if ( addbevels ) {
//NOTE: we first have to get the mins and maxs of the brush before
// creating the brush bevels... the mins and maxs are used to
// create them. so we call MakeBrushWindings to get the mins
// and maxs and then after creating the bevels we free the
// windings because they are created for all sides (including
// bevels) a little later
AAS_MakeBrushWindings( brush );
AddBrushBevels( brush );
FreeBrushWindings( brush );
} //end if
//NOTE: add the brush to the WORLD entity!!!
mapent = &entities[0];
//there's at least one new brush for now
nummapbrushes++;
mapent->numbrushes++;
//liquid brushes are expanded for the maximum possible bounding box
if ( brush->contents & ( CONTENTS_WATER
| CONTENTS_LAVA
| CONTENTS_SLIME
| CONTENTS_TELEPORTER
| CONTENTS_JUMPPAD
| CONTENTS_DONOTENTER
| CONTENTS_DONOTENTER_LARGE
| CONTENTS_MOVER
) ) {
brush->expansionbbox = 0;
//NOTE: the first bounding box is the max
//FIXME: use max bounding box created from all bboxes
AAS_ExpandMapBrush( brush, cfg.bboxes[0].mins, cfg.bboxes[0].maxs );
AAS_MakeBrushWindings( brush );
} //end if
//area portal brushes are NOT expanded
else if ( brush->contents & CONTENTS_CLUSTERPORTAL ) {
brush->expansionbbox = 0;
//NOTE: the first bounding box is the max
//FIXME: use max bounding box created from all bboxes
AAS_ExpandMapBrush( brush, cfg.bboxes[0].mins, cfg.bboxes[0].maxs );
AAS_MakeBrushWindings( brush );
} //end if
//all solid brushes are expanded for all bounding boxes
else if ( brush->contents & ( CONTENTS_SOLID
| CONTENTS_LADDER
) ) {
//brush for the first bounding box
bboxbrushes[0] = brush;
//make a copy for the other bounding boxes
for ( i = 1; i < cfg.numbboxes; i++ )
{
bboxbrushes[i] = AAS_CopyMapBrush( brush, mapent );
} //end for
//expand every brush for it's bounding box and create windings
for ( i = 0; i < cfg.numbboxes; i++ )
{
AAS_ExpandMapBrush( bboxbrushes[i], cfg.bboxes[i].mins, cfg.bboxes[i].maxs );
bboxbrushes[i]->expansionbbox = cfg.bboxes[i].presencetype;
AAS_MakeBrushWindings( bboxbrushes[i] );
} //end for
} //end else
} //end of the function AAS_CreateMapBrushes