mirror of
https://github.com/id-Software/RTCW-MP.git
synced 2026-03-20 00:49:40 +01:00
The Return to Castle Wolfenstein Multiplayer sources as originally released under the GPL license on August 12, 2010.
This commit is contained in:
838
src/bspc/aas_map.c
Normal file
838
src/bspc/aas_map.c
Normal 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
|
||||
Reference in New Issue
Block a user