2010-02-15 23:26:55 +00:00
/*
Copyright ( C ) 1996 - 2001 Id Software , Inc .
Copyright ( C ) 2002 - 2009 John Fitzgibbons and others
Copyright ( C ) 2007 - 2008 Kristian Duske
2014-09-22 08:55:46 +00:00
Copyright ( C ) 2010 - 2014 QuakeSpasm developers
2010-02-15 23:26:55 +00:00
This program 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 2
of the License , or ( at your option ) any later version .
This program 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 this program ; if not , write to the Free Software
Foundation , Inc . , 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA .
*/
// world.c -- world query functions
# include "quakedef.h"
/*
entities never clip against themselves , or their owner
line of sight checks trace - > crosscontent , but bullets don ' t
*/
typedef struct
{
vec3_t boxmins , boxmaxs ; // enclose the test object along entire move
float * mins , * maxs ; // size of the moving object
vec3_t mins2 , maxs2 ; // size when clipping against mosnters
float * start , * end ;
trace_t trace ;
int type ;
2019-09-13 17:51:16 +00:00
unsigned int hitcontents ; //content types to impact upon... (1<<-CONTENTS_FOO) bitmask
2010-02-15 23:26:55 +00:00
edict_t * passedict ;
} moveclip_t ;
int SV_HullPointContents ( hull_t * hull , int num , vec3_t p ) ;
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
HULL BOXES
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
static hull_t box_hull ;
static mclipnode_t box_clipnodes [ 6 ] ; //johnfitz -- was dclipnode_t
static mplane_t box_planes [ 6 ] ;
/*
= = = = = = = = = = = = = = = = = = =
SV_InitBoxHull
Set up the planes and clipnodes so that the six floats of a bounding box
can just be stored out and get a proper hull_t structure .
= = = = = = = = = = = = = = = = = = =
*/
void SV_InitBoxHull ( void )
{
int i ;
int side ;
box_hull . clipnodes = box_clipnodes ;
box_hull . planes = box_planes ;
box_hull . firstclipnode = 0 ;
box_hull . lastclipnode = 5 ;
for ( i = 0 ; i < 6 ; i + + )
{
box_clipnodes [ i ] . planenum = i ;
side = i & 1 ;
box_clipnodes [ i ] . children [ side ] = CONTENTS_EMPTY ;
if ( i ! = 5 )
box_clipnodes [ i ] . children [ side ^ 1 ] = i + 1 ;
else
box_clipnodes [ i ] . children [ side ^ 1 ] = CONTENTS_SOLID ;
box_planes [ i ] . type = i > > 1 ;
box_planes [ i ] . normal [ i > > 1 ] = 1 ;
}
}
/*
= = = = = = = = = = = = = = = = = = =
SV_HullForBox
To keep everything totally uniform , bounding boxes are turned into small
BSP trees instead of being compared directly .
= = = = = = = = = = = = = = = = = = =
*/
hull_t * SV_HullForBox ( vec3_t mins , vec3_t maxs )
{
box_planes [ 0 ] . dist = maxs [ 0 ] ;
box_planes [ 1 ] . dist = mins [ 0 ] ;
box_planes [ 2 ] . dist = maxs [ 1 ] ;
box_planes [ 3 ] . dist = mins [ 1 ] ;
box_planes [ 4 ] . dist = maxs [ 2 ] ;
box_planes [ 5 ] . dist = mins [ 2 ] ;
return & box_hull ;
}
/*
= = = = = = = = = = = = = = = =
SV_HullForEntity
Returns a hull that can be used for testing or clipping an object of mins / maxs
size .
Offset is filled in to contain the adjustment that must be added to the
testing object ' s origin to get a point to use with the returned hull .
= = = = = = = = = = = = = = = =
*/
hull_t * SV_HullForEntity ( edict_t * ent , vec3_t mins , vec3_t maxs , vec3_t offset )
{
2012-05-30 08:56:06 +00:00
qmodel_t * model ;
2010-02-15 23:26:55 +00:00
vec3_t size ;
vec3_t hullmins , hullmaxs ;
hull_t * hull ;
// decide which clipping hull to use, based on the size
2021-09-08 01:44:57 +00:00
if ( ent - > v . solid = = SOLID_BSP | | ent - > v . solid = = SOLID_EXT_BSPTRIGGER )
2010-02-15 23:26:55 +00:00
{ // explicit hulls in the BSP model
2019-01-30 01:53:33 +00:00
if ( ent - > v . movetype ! = MOVETYPE_PUSH & & ! pr_checkextension . value )
2019-01-31 03:20:19 +00:00
Con_Warning ( " SOLID_BSP without MOVETYPE_PUSH (%s at %f %f %f) \n " ,
2017-08-24 03:06:56 +00:00
PR_GetString ( ent - > v . classname ) , ent - > v . origin [ 0 ] , ent - > v . origin [ 1 ] , ent - > v . origin [ 2 ] ) ;
2010-02-15 23:26:55 +00:00
2020-09-03 10:39:38 +00:00
model = qcvm - > GetModel ( ent - > v . modelindex ) ;
2010-02-15 23:26:55 +00:00
if ( ! model | | model - > type ! = mod_brush )
2019-01-30 01:53:33 +00:00
{
2019-01-31 03:20:19 +00:00
Con_Warning ( " SOLID_BSP with a non bsp model (%s at %f %f %f) \n " ,
2017-08-24 03:06:56 +00:00
PR_GetString ( ent - > v . classname ) , ent - > v . origin [ 0 ] , ent - > v . origin [ 1 ] , ent - > v . origin [ 2 ] ) ;
2019-01-30 01:53:33 +00:00
goto nohitmeshsupport ;
}
2010-02-15 23:26:55 +00:00
VectorSubtract ( maxs , mins , size ) ;
if ( size [ 0 ] < 3 )
hull = & model - > hulls [ 0 ] ;
else if ( size [ 0 ] < = 32 )
hull = & model - > hulls [ 1 ] ;
else
hull = & model - > hulls [ 2 ] ;
// calculate an offset value to center the origin
VectorSubtract ( hull - > clip_mins , mins , offset ) ;
VectorAdd ( offset , ent - > v . origin , offset ) ;
}
else
{ // create a temp hull from bounding box sizes
2019-01-30 01:53:33 +00:00
nohitmeshsupport :
2010-02-15 23:26:55 +00:00
VectorSubtract ( ent - > v . mins , maxs , hullmins ) ;
VectorSubtract ( ent - > v . maxs , mins , hullmaxs ) ;
hull = SV_HullForBox ( hullmins , hullmaxs ) ;
VectorCopy ( ent - > v . origin , offset ) ;
}
return hull ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
ENTITY AREA CHECKING
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
= = = = = = = = = = = = = = =
SV_CreateAreaNode
= = = = = = = = = = = = = = =
*/
areanode_t * SV_CreateAreaNode ( int depth , vec3_t mins , vec3_t maxs )
{
areanode_t * anode ;
vec3_t size ;
vec3_t mins1 , maxs1 , mins2 , maxs2 ;
2018-05-01 00:35:14 +00:00
anode = & qcvm - > areanodes [ qcvm - > numareanodes ] ;
qcvm - > numareanodes + + ;
2010-02-15 23:26:55 +00:00
ClearLink ( & anode - > trigger_edicts ) ;
ClearLink ( & anode - > solid_edicts ) ;
if ( depth = = AREA_DEPTH )
{
anode - > axis = - 1 ;
anode - > children [ 0 ] = anode - > children [ 1 ] = NULL ;
return anode ;
}
VectorSubtract ( maxs , mins , size ) ;
if ( size [ 0 ] > size [ 1 ] )
anode - > axis = 0 ;
else
anode - > axis = 1 ;
anode - > dist = 0.5 * ( maxs [ anode - > axis ] + mins [ anode - > axis ] ) ;
VectorCopy ( mins , mins1 ) ;
VectorCopy ( mins , mins2 ) ;
VectorCopy ( maxs , maxs1 ) ;
VectorCopy ( maxs , maxs2 ) ;
maxs1 [ anode - > axis ] = mins2 [ anode - > axis ] = anode - > dist ;
anode - > children [ 0 ] = SV_CreateAreaNode ( depth + 1 , mins2 , maxs2 ) ;
anode - > children [ 1 ] = SV_CreateAreaNode ( depth + 1 , mins1 , maxs1 ) ;
return anode ;
}
/*
= = = = = = = = = = = = = = =
SV_ClearWorld
= = = = = = = = = = = = = = =
*/
void SV_ClearWorld ( void )
{
SV_InitBoxHull ( ) ;
2018-05-01 00:35:14 +00:00
memset ( qcvm - > areanodes , 0 , sizeof ( qcvm - > areanodes ) ) ;
qcvm - > numareanodes = 0 ;
SV_CreateAreaNode ( 0 , qcvm - > worldmodel - > mins , qcvm - > worldmodel - > maxs ) ;
2010-02-15 23:26:55 +00:00
}
/*
= = = = = = = = = = = = = = =
SV_UnlinkEdict
= = = = = = = = = = = = = = =
*/
void SV_UnlinkEdict ( edict_t * ent )
{
if ( ! ent - > area . prev )
return ; // not linked in anywhere
RemoveLink ( & ent - > area ) ;
ent - > area . prev = ent - > area . next = NULL ;
}
2023-07-22 16:40:33 +00:00
# include "pmove.h"
static void
World_AreaAddEntsToPmove ( edict_t * ignore , areanode_t * node , vec3_t boxminmax [ 2 ] )
{
link_t * l , * next ;
edict_t * other ;
// touch linked edicts
for ( l = node - > solid_edicts . next ; l ! = & node - > solid_edicts ; l = next )
{
next = l - > next ;
other = EDICT_FROM_AREA ( l ) ;
if ( other = = ignore )
continue ;
if ( other - > v . solid ! = SOLID_BBOX & & other - > v . solid ! = SOLID_SLIDEBOX & & other - > v . solid ! = SOLID_BSP )
continue ;
if ( boxminmax [ 0 ] [ 0 ] > other - > v . absmax [ 0 ]
| | boxminmax [ 0 ] [ 1 ] > other - > v . absmax [ 1 ]
| | boxminmax [ 0 ] [ 2 ] > other - > v . absmax [ 2 ]
| | boxminmax [ 1 ] [ 0 ] < other - > v . absmin [ 0 ]
| | boxminmax [ 1 ] [ 1 ] < other - > v . absmin [ 1 ]
| | boxminmax [ 1 ] [ 2 ] < other - > v . absmin [ 2 ] )
continue ;
2023-07-25 13:21:02 +00:00
if ( ignore )
{
if ( PROG_TO_EDICT ( other - > v . owner ) = = ignore )
continue ; // don't clip against own missiles
if ( PROG_TO_EDICT ( ignore - > v . owner ) = = other )
continue ; // don't clip against owner
}
2023-07-22 16:40:33 +00:00
if ( pmove . numphysent = = countof ( pmove . physents ) )
return ; //too many... ooer.
pmove . physents [ pmove . numphysent ] . info = NUM_FOR_EDICT ( other ) ;
pmove . physents [ pmove . numphysent ] . model = ( other - > v . solid = = SOLID_BSP ) ? qcvm - > GetModel ( other - > v . modelindex ) : NULL ;
VectorCopy ( other - > v . origin , pmove . physents [ pmove . numphysent ] . origin ) ;
VectorCopy ( other - > v . mins , pmove . physents [ pmove . numphysent ] . mins ) ;
VectorCopy ( other - > v . maxs , pmove . physents [ pmove . numphysent ] . maxs ) ;
VectorCopy ( other - > v . angles , pmove . physents [ pmove . numphysent ] . angles ) ;
pmove . physents [ pmove . numphysent ] . forcecontentsmask = 0 ;
if ( other - > v . skin < 0 )
switch ( ( int ) other - > v . skin )
{
case CONTENTS_WATER : pmove . physents [ pmove . numphysent ] . forcecontentsmask = CONTENTBIT_WATER ; break ;
case CONTENTS_LAVA : pmove . physents [ pmove . numphysent ] . forcecontentsmask = CONTENTBIT_LAVA ; break ;
case CONTENTS_SLIME : pmove . physents [ pmove . numphysent ] . forcecontentsmask = CONTENTBIT_SLIME ; break ;
case CONTENTS_SKY : pmove . physents [ pmove . numphysent ] . forcecontentsmask = CONTENTBIT_SKY ; break ;
case CONTENTS_CLIP : pmove . physents [ pmove . numphysent ] . forcecontentsmask = CONTENTBIT_CLIP ; break ;
case CONTENTS_LADDER : pmove . physents [ pmove . numphysent ] . forcecontentsmask = CONTENTBIT_LADDER ; break ;
}
pmove . numphysent + + ;
}
// recurse down both sides
if ( node - > axis = = - 1 )
return ;
if ( boxminmax [ 1 ] [ node - > axis ] > node - > dist )
World_AreaAddEntsToPmove ( ignore , node - > children [ 0 ] , boxminmax ) ;
if ( boxminmax [ 0 ] [ node - > axis ] < node - > dist )
World_AreaAddEntsToPmove ( ignore , node - > children [ 1 ] , boxminmax ) ;
}
void World_AddEntsToPmove ( edict_t * ignore , vec3_t boxminmax [ 2 ] )
{
2023-07-25 13:21:02 +00:00
if ( ignore )
pmove . skipent = NUM_FOR_EDICT ( ignore ) ;
2023-07-22 16:40:33 +00:00
pmove . physents [ 0 ] . model = qcvm - > worldmodel ;
2023-07-25 13:21:02 +00:00
VectorClear ( pmove . physents [ 0 ] . origin ) ;
VectorClear ( pmove . physents [ 0 ] . angles ) ;
pmove . physents [ 0 ] . forcecontentsmask = 0 ;
pmove . physents [ 0 ] . info = 0 ;
2023-07-22 16:40:33 +00:00
pmove . numphysent = 1 ;
World_AreaAddEntsToPmove ( ignore , qcvm - > areanodes , boxminmax ) ;
//csqc needs to be able to clip against the server's ents, too
if ( qcvm = = & cl . qcvm )
{
entity_t * touch ;
int i ;
for ( i = 1 , touch = cl . entities + 1 ; i < cl . num_entities ; i + + , touch + + )
{
if ( ! touch - > model )
continue ;
if ( touch - > netstate . solidsize = = ES_SOLID_NOT )
continue ; //not relevant
if ( pmove . numphysent = = countof ( pmove . physents ) )
return ; //too many... ooer.
if ( touch - > netstate . solidsize = = ES_SOLID_BSP )
{
if ( ! touch - > model | | touch - > model - > type ! = mod_brush )
continue ;
VectorCopy ( touch - > model - > mins , pmove . physents [ pmove . numphysent ] . mins ) ;
VectorCopy ( touch - > model - > maxs , pmove . physents [ pmove . numphysent ] . maxs ) ;
pmove . physents [ pmove . numphysent ] . model = touch - > model ;
}
else
{
float * touch_mins = pmove . physents [ pmove . numphysent ] . mins ;
float * touch_maxs = pmove . physents [ pmove . numphysent ] . maxs ;
touch_maxs [ 0 ] = touch_maxs [ 1 ] = touch - > netstate . solidsize & 255 ;
touch_mins [ 0 ] = touch_mins [ 1 ] = - touch_maxs [ 0 ] ;
touch_mins [ 2 ] = - ( int ) ( ( touch - > netstate . solidsize > > 8 ) & 255 ) ;
touch_maxs [ 2 ] = ( int ) ( ( touch - > netstate . solidsize > > 16 ) & 65535 ) - 32768 ;
pmove . physents [ pmove . numphysent ] . model = NULL ;
}
pmove . physents [ pmove . numphysent ] . info = - i ; //kinda backwards, but oh well. the csqc won't know their numbers.
VectorCopy ( touch - > origin , pmove . physents [ pmove . numphysent ] . origin ) ;
VectorCopy ( touch - > angles , pmove . physents [ pmove . numphysent ] . angles ) ;
pmove . physents [ pmove . numphysent ] . forcecontentsmask = 0 ;
if ( touch - > skinnum < 0 )
switch ( touch - > skinnum )
{
case CONTENTS_WATER : pmove . physents [ pmove . numphysent ] . forcecontentsmask = CONTENTBIT_WATER ; break ;
case CONTENTS_LAVA : pmove . physents [ pmove . numphysent ] . forcecontentsmask = CONTENTBIT_LAVA ; break ;
case CONTENTS_SLIME : pmove . physents [ pmove . numphysent ] . forcecontentsmask = CONTENTBIT_SLIME ; break ;
case CONTENTS_SKY : pmove . physents [ pmove . numphysent ] . forcecontentsmask = CONTENTBIT_SKY ; break ;
case CONTENTS_CLIP : pmove . physents [ pmove . numphysent ] . forcecontentsmask = CONTENTBIT_CLIP ; break ;
case CONTENTS_LADDER : pmove . physents [ pmove . numphysent ] . forcecontentsmask = CONTENTBIT_LADDER ; break ;
}
pmove . numphysent + + ;
}
}
}
2010-02-15 23:26:55 +00:00
/*
= = = = = = = = = = = = = = = = = = = =
2017-08-28 02:15:04 +00:00
SV_AreaTriggerEdicts
Spike - - just builds a list of entities within the area , rather than walking
them and risking the list getting corrupt .
2010-02-15 23:26:55 +00:00
= = = = = = = = = = = = = = = = = = = =
*/
2017-08-28 02:15:04 +00:00
static void
SV_AreaTriggerEdicts ( edict_t * ent , areanode_t * node , edict_t * * list , int * listcount , const int listspace )
2010-02-15 23:26:55 +00:00
{
link_t * l , * next ;
edict_t * touch ;
// touch linked edicts
for ( l = node - > trigger_edicts . next ; l ! = & node - > trigger_edicts ; l = next )
{
next = l - > next ;
touch = EDICT_FROM_AREA ( l ) ;
2017-08-28 02:15:04 +00:00
if ( touch = = ent )
continue ;
2021-09-08 01:44:57 +00:00
if ( ! touch - > v . touch | | ( touch - > v . solid ! = SOLID_TRIGGER & & touch - > v . solid ! = SOLID_EXT_BSPTRIGGER ) )
2017-08-28 02:15:04 +00:00
continue ;
if ( ent - > v . absmin [ 0 ] > touch - > v . absmax [ 0 ]
| | ent - > v . absmin [ 1 ] > touch - > v . absmax [ 1 ]
| | ent - > v . absmin [ 2 ] > touch - > v . absmax [ 2 ]
| | ent - > v . absmax [ 0 ] < touch - > v . absmin [ 0 ]
| | ent - > v . absmax [ 1 ] < touch - > v . absmin [ 1 ]
| | ent - > v . absmax [ 2 ] < touch - > v . absmin [ 2 ] )
continue ;
if ( * listcount = = listspace )
return ; // should never happen
list [ * listcount ] = touch ;
( * listcount ) + + ;
}
// recurse down both sides
if ( node - > axis = = - 1 )
return ;
if ( ent - > v . absmax [ node - > axis ] > node - > dist )
SV_AreaTriggerEdicts ( ent , node - > children [ 0 ] , list , listcount , listspace ) ;
if ( ent - > v . absmin [ node - > axis ] < node - > dist )
SV_AreaTriggerEdicts ( ent , node - > children [ 1 ] , list , listcount , listspace ) ;
}
/*
= = = = = = = = = = = = = = = = = = = =
SV_TouchLinks
ericw - - copy the touching edicts to an array ( on the hunk ) so we can avoid
iteating the trigger_edicts linked list while calling PR_ExecuteProgram
which could potentially corrupt the list while it ' s being iterated .
Based on code from Spike .
= = = = = = = = = = = = = = = = = = = =
*/
void SV_TouchLinks ( edict_t * ent )
{
edict_t * * list ;
edict_t * touch ;
int old_self , old_other ;
int i , listcount ;
int mark ;
mark = Hunk_LowMark ( ) ;
2018-05-01 00:35:14 +00:00
list = ( edict_t * * ) Hunk_Alloc ( qcvm - > num_edicts * sizeof ( edict_t * ) ) ;
2017-08-28 02:15:04 +00:00
listcount = 0 ;
2018-05-01 00:35:14 +00:00
SV_AreaTriggerEdicts ( ent , qcvm - > areanodes , list , & listcount , qcvm - > num_edicts ) ;
2017-08-28 02:15:04 +00:00
for ( i = 0 ; i < listcount ; i + + )
{
touch = list [ i ] ;
// re-validate in case of PR_ExecuteProgram having side effects that make
// edicts later in the list no longer touch
2010-02-15 23:26:55 +00:00
if ( touch = = ent )
continue ;
2021-09-08 01:44:57 +00:00
if ( ! touch - > v . touch | | ( touch - > v . solid ! = SOLID_TRIGGER & & touch - > v . solid ! = SOLID_EXT_BSPTRIGGER ) )
2010-02-15 23:26:55 +00:00
continue ;
if ( ent - > v . absmin [ 0 ] > touch - > v . absmax [ 0 ]
| | ent - > v . absmin [ 1 ] > touch - > v . absmax [ 1 ]
| | ent - > v . absmin [ 2 ] > touch - > v . absmax [ 2 ]
| | ent - > v . absmax [ 0 ] < touch - > v . absmin [ 0 ]
| | ent - > v . absmax [ 1 ] < touch - > v . absmin [ 1 ]
| | ent - > v . absmax [ 2 ] < touch - > v . absmin [ 2 ] )
continue ;
2021-09-08 01:44:57 +00:00
if ( touch - > v . solid = = SOLID_EXT_BSPTRIGGER )
{
if ( ! SV_ClipMoveToEntity ( touch , ent - > v . origin , ent - > v . mins , ent - > v . maxs , ent - > v . origin , CONTENTMASK_ANYSOLID ) . startsolid )
continue ;
}
2010-02-15 23:26:55 +00:00
old_self = pr_global_struct - > self ;
old_other = pr_global_struct - > other ;
pr_global_struct - > self = EDICT_TO_PROG ( touch ) ;
pr_global_struct - > other = EDICT_TO_PROG ( ent ) ;
2018-05-01 00:35:14 +00:00
pr_global_struct - > time = qcvm - > time ;
2010-02-15 23:26:55 +00:00
PR_ExecuteProgram ( touch - > v . touch ) ;
pr_global_struct - > self = old_self ;
pr_global_struct - > other = old_other ;
}
2017-08-28 02:15:04 +00:00
// free hunk-allocated edicts array
Hunk_FreeToLowMark ( mark ) ;
2010-02-15 23:26:55 +00:00
}
/*
= = = = = = = = = = = = = = =
SV_FindTouchedLeafs
= = = = = = = = = = = = = = =
*/
void SV_FindTouchedLeafs ( edict_t * ent , mnode_t * node )
{
mplane_t * splitplane ;
mleaf_t * leaf ;
int sides ;
int leafnum ;
if ( node - > contents = = CONTENTS_SOLID )
return ;
// add an efrag if the node is a leaf
if ( node - > contents < 0 )
{
if ( ent - > num_leafs = = MAX_ENT_LEAFS )
return ;
leaf = ( mleaf_t * ) node ;
2018-05-01 00:35:14 +00:00
leafnum = leaf - qcvm - > worldmodel - > leafs - 1 ;
2010-02-15 23:26:55 +00:00
ent - > leafnums [ ent - > num_leafs ] = leafnum ;
ent - > num_leafs + + ;
return ;
}
// NODE_MIXED
splitplane = node - > plane ;
sides = BOX_ON_PLANE_SIDE ( ent - > v . absmin , ent - > v . absmax , splitplane ) ;
// recurse down the contacted sides
if ( sides & 1 )
SV_FindTouchedLeafs ( ent , node - > children [ 0 ] ) ;
if ( sides & 2 )
SV_FindTouchedLeafs ( ent , node - > children [ 1 ] ) ;
}
/*
= = = = = = = = = = = = = = =
SV_LinkEdict
= = = = = = = = = = = = = = =
*/
void SV_LinkEdict ( edict_t * ent , qboolean touch_triggers )
{
areanode_t * node ;
if ( ent - > area . prev )
SV_UnlinkEdict ( ent ) ; // unlink from old position
2018-05-01 00:35:14 +00:00
if ( ent = = qcvm - > edicts )
2010-02-15 23:26:55 +00:00
return ; // don't add the world
if ( ent - > free )
return ;
// set the abs box
2022-08-23 09:10:17 +00:00
VectorAdd ( ent - > v . origin , ent - > v . mins , ent - > v . absmin ) ;
VectorAdd ( ent - > v . origin , ent - > v . maxs , ent - > v . absmax ) ;
if ( ( ent - > v . solid = = SOLID_BSP | | ent - > v . solid = = SOLID_EXT_BSPTRIGGER ) & & ( ent - > v . angles [ 0 ] | | ent - > v . angles [ 1 ] | | ent - > v . angles [ 2 ] ) )
{
if ( qcvm - > rotatingbmodel )
{ // expand for rotation the lame way. hopefully there's an origin brush in there.
int i ;
float v1 , v2 ;
vec3_t max ;
//q2 method
for ( i = 0 ; i < 3 ; i + + )
{
v1 = fabs ( ent - > v . mins [ i ] ) ;
v2 = fabs ( ent - > v . maxs [ i ] ) ;
max [ i ] = q_max ( v1 , v2 ) ;
}
v1 = sqrt ( DotProduct ( max , max ) ) ;
for ( i = 0 ; i < 3 ; i + + )
{
ent - > v . absmin [ i ] = ent - > v . origin [ i ] - v1 ;
ent - > v . absmax [ i ] = ent - > v . origin [ i ] + v1 ;
}
2020-04-06 23:56:15 +00:00
}
2022-08-23 09:10:17 +00:00
else if ( ! qcvm - > warned_rotatingbmodel )
2020-04-06 23:56:15 +00:00
{
2022-08-23 09:10:17 +00:00
Con_Warning ( " %s( \" %s \" ) has angles set, but DP_SV_ROTATINGBMODEL is not enabled \n " , ( ent - > v . solid = = SOLID_EXT_BSPTRIGGER ) ? " SOLID_BSPTRIGGER " : " SOLID_BSP " , PR_GetString ( ent - > v . classname ) ) ;
qcvm - > warned_rotatingbmodel = true ;
2020-04-06 23:56:15 +00:00
}
}
2010-02-15 23:26:55 +00:00
//
// to make items easier to pick up and allow them to be grabbed off
// of shelves, the abs sizes are expanded
//
if ( ( int ) ent - > v . flags & FL_ITEM )
{
ent - > v . absmin [ 0 ] - = 15 ;
ent - > v . absmin [ 1 ] - = 15 ;
ent - > v . absmax [ 0 ] + = 15 ;
ent - > v . absmax [ 1 ] + = 15 ;
}
else
{ // because movement is clipped an epsilon away from an actual edge,
// we must fully check even when bounding boxes don't quite touch
ent - > v . absmin [ 0 ] - = 1 ;
ent - > v . absmin [ 1 ] - = 1 ;
ent - > v . absmin [ 2 ] - = 1 ;
ent - > v . absmax [ 0 ] + = 1 ;
ent - > v . absmax [ 1 ] + = 1 ;
ent - > v . absmax [ 2 ] + = 1 ;
}
// link to PVS leafs
ent - > num_leafs = 0 ;
if ( ent - > v . modelindex )
2018-05-01 00:35:14 +00:00
SV_FindTouchedLeafs ( ent , qcvm - > worldmodel - > nodes ) ;
2010-02-15 23:26:55 +00:00
if ( ent - > v . solid = = SOLID_NOT )
return ;
// find the first node that the ent's box crosses
2018-05-01 00:35:14 +00:00
node = qcvm - > areanodes ;
2010-02-15 23:26:55 +00:00
while ( 1 )
{
if ( node - > axis = = - 1 )
break ;
if ( ent - > v . absmin [ node - > axis ] > node - > dist )
node = node - > children [ 0 ] ;
else if ( ent - > v . absmax [ node - > axis ] < node - > dist )
node = node - > children [ 1 ] ;
else
break ; // crosses the node
}
// link it in
2021-09-08 01:44:57 +00:00
if ( ent - > v . solid = = SOLID_TRIGGER | | ent - > v . solid = = SOLID_EXT_BSPTRIGGER )
2010-02-15 23:26:55 +00:00
InsertLinkBefore ( & ent - > area , & node - > trigger_edicts ) ;
else
InsertLinkBefore ( & ent - > area , & node - > solid_edicts ) ;
// if touch_triggers, touch all entities at this node and decend for more
if ( touch_triggers )
2017-08-28 02:15:04 +00:00
SV_TouchLinks ( ent ) ;
2010-02-15 23:26:55 +00:00
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
POINT TESTING IN HULLS
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
= = = = = = = = = = = = = = = = = =
SV_HullPointContents
= = = = = = = = = = = = = = = = = =
*/
int SV_HullPointContents ( hull_t * hull , int num , vec3_t p )
{
float d ;
mclipnode_t * node ; //johnfitz -- was dclipnode_t
mplane_t * plane ;
while ( num > = 0 )
{
if ( num < hull - > firstclipnode | | num > hull - > lastclipnode )
Sys_Error ( " SV_HullPointContents: bad node number " ) ;
node = hull - > clipnodes + num ;
plane = hull - > planes + node - > planenum ;
if ( plane - > type < 3 )
d = p [ plane - > type ] - plane - > dist ;
else
2016-02-01 22:41:15 +00:00
d = DoublePrecisionDotProduct ( plane - > normal , p ) - plane - > dist ;
2010-02-15 23:26:55 +00:00
if ( d < 0 )
num = node - > children [ 1 ] ;
else
num = node - > children [ 0 ] ;
}
return num ;
}
/*
= = = = = = = = = = = = = = = = = =
SV_PointContents
= = = = = = = = = = = = = = = = = =
*/
int SV_PointContents ( vec3_t p )
{
int cont ;
2018-05-01 00:35:14 +00:00
cont = SV_HullPointContents ( & qcvm - > worldmodel - > hulls [ 0 ] , 0 , p ) ;
2010-02-15 23:26:55 +00:00
if ( cont < = CONTENTS_CURRENT_0 & & cont > = CONTENTS_CURRENT_DOWN )
cont = CONTENTS_WATER ;
return cont ;
}
int SV_TruePointContents ( vec3_t p )
{
2018-05-01 00:35:14 +00:00
return SV_HullPointContents ( & qcvm - > worldmodel - > hulls [ 0 ] , 0 , p ) ;
2010-02-15 23:26:55 +00:00
}
2019-09-13 17:51:16 +00:00
int SV_PointContentsAllBsps ( vec3_t p , edict_t * forent )
{
trace_t trace = SV_Move ( p , vec3_origin , vec3_origin , p , MOVE_NOMONSTERS | MOVE_HITALLCONTENTS , forent ) ;
if ( trace . contents < = CONTENTS_CURRENT_0 & & trace . contents > = CONTENTS_CURRENT_DOWN )
trace . contents = CONTENTS_WATER ;
return trace . contents ;
}
2010-02-15 23:26:55 +00:00
//===========================================================================
/*
= = = = = = = = = = = =
SV_TestEntityPosition
This could be a lot more efficient . . .
= = = = = = = = = = = =
*/
edict_t * SV_TestEntityPosition ( edict_t * ent )
{
trace_t trace ;
2021-09-07 23:11:30 +00:00
trace = SV_Move ( ent - > v . origin , ent - > v . mins , ent - > v . maxs , ent - > v . origin , ( ( ent - > v . solid = = SOLID_NOT | | ent - > v . solid = = SOLID_TRIGGER | | ent - > v . solid = = SOLID_EXT_BSPTRIGGER ) ? MOVE_NOMONSTERS : 0 ) , ent ) ;
2010-02-15 23:26:55 +00:00
if ( trace . startsolid )
2018-05-01 00:35:14 +00:00
return qcvm - > edicts ;
2010-02-15 23:26:55 +00:00
return NULL ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
LINE TESTING IN HULLS
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2018-07-14 23:52:34 +00:00
enum
{
rht_solid ,
rht_empty ,
rht_impact
} ;
struct rhtctx_s
{
2021-03-06 06:04:42 +00:00
unsigned int hitcontents ;
2018-07-14 23:52:34 +00:00
vec3_t start , end ;
mclipnode_t * clipnodes ;
mplane_t * planes ;
} ;
# define VectorNegate(a,b) ((b)[0]=-(a)[0],(b)[1]=-(a)[1],(b)[2]=-(a)[2])
# define FloatInterpolate(a, bness, b, c) ((c) = (a) + (b - a)*bness)
# define VectorInterpolate(a, bness, b, c) FloatInterpolate((a)[0], bness, (b)[0], (c)[0]),FloatInterpolate((a)[1], bness, (b)[1], (c)[1]),FloatInterpolate((a)[2], bness, (b)[2], (c)[2])
2010-02-15 23:26:55 +00:00
/*
= = = = = = = = = = = = = = = = = =
2018-07-14 23:52:34 +00:00
Q1BSP_RecursiveHullTrace
This does the core traceline / tracebox logic .
This version is from FTE and attempts to be more numerically stable than vanilla .
This is achieved by recursing at the actual decision points instead of vanilla ' s habit of vanilla ' s habit of using points that are outside of the child ' s volume .
It also uses itself to test solidity on the other side of the node , which ensures consistent precision .
The actual collision point is ( still ) biased by an epsilon , so the end point shouldn ' t be inside walls either way .
FTE ' s version ' should ' be more compatible with vanilla than DP ' s ( which doesn ' t take care with allsolid ) .
ezQuake also has a version of this logic , but I trust mine more .
2010-02-15 23:26:55 +00:00
= = = = = = = = = = = = = = = = = =
*/
2018-07-14 23:52:34 +00:00
static int Q1BSP_RecursiveHullTrace ( struct rhtctx_s * ctx , int num , float p1f , float p2f , vec3_t p1 , vec3_t p2 , trace_t * trace )
2010-02-15 23:26:55 +00:00
{
2018-07-14 23:52:34 +00:00
mclipnode_t * node ;
2010-02-15 23:26:55 +00:00
mplane_t * plane ;
float t1 , t2 ;
vec3_t mid ;
int side ;
float midf ;
2018-07-14 23:52:34 +00:00
int rht ;
reenter :
2010-02-15 23:26:55 +00:00
if ( num < 0 )
{
2018-07-14 23:52:34 +00:00
/*hit a leaf*/
2019-09-13 17:51:16 +00:00
trace - > contents = num ;
2021-03-06 06:04:42 +00:00
if ( ctx - > hitcontents & CONTENTMASK_FROMQ1 ( num ) )
2018-07-14 23:52:34 +00:00
{
if ( trace - > allsolid )
trace - > startsolid = true ;
return rht_solid ;
}
else
2010-02-15 23:26:55 +00:00
{
2021-09-25 01:18:23 +00:00
trace - > allsolid = false ;
2010-02-15 23:26:55 +00:00
if ( num = = CONTENTS_EMPTY )
trace - > inopen = true ;
2021-03-06 06:04:42 +00:00
else if ( num ! = CONTENTS_SOLID )
2010-02-15 23:26:55 +00:00
trace - > inwater = true ;
2018-07-14 23:52:34 +00:00
return rht_empty ;
2010-02-15 23:26:55 +00:00
}
}
2018-07-14 23:52:34 +00:00
/*its a node*/
2010-02-15 23:26:55 +00:00
2018-07-14 23:52:34 +00:00
/*get the node info*/
node = ctx - > clipnodes + num ;
plane = ctx - > planes + node - > planenum ;
2010-02-15 23:26:55 +00:00
if ( plane - > type < 3 )
{
t1 = p1 [ plane - > type ] - plane - > dist ;
t2 = p2 [ plane - > type ] - plane - > dist ;
}
else
{
2018-07-15 23:59:35 +00:00
t1 = DoublePrecisionDotProduct ( plane - > normal , p1 ) - plane - > dist ;
t2 = DoublePrecisionDotProduct ( plane - > normal , p2 ) - plane - > dist ;
2010-02-15 23:26:55 +00:00
}
2018-07-14 23:52:34 +00:00
/*if its completely on one side, resume on that side*/
2010-02-15 23:26:55 +00:00
if ( t1 > = 0 & & t2 > = 0 )
2018-07-14 23:52:34 +00:00
{
//return Q1BSP_RecursiveHullTrace (hull, node->children[0], p1f, p2f, p1, p2, trace);
num = node - > children [ 0 ] ;
goto reenter ;
}
2010-02-15 23:26:55 +00:00
if ( t1 < 0 & & t2 < 0 )
2018-07-14 23:52:34 +00:00
{
//return Q1BSP_RecursiveHullTrace (hull, node->children[1], p1f, p2f, p1, p2, trace);
num = node - > children [ 1 ] ;
goto reenter ;
}
2010-02-15 23:26:55 +00:00
2018-07-14 23:52:34 +00:00
if ( plane - > type < 3 )
2010-02-15 23:26:55 +00:00
{
2018-07-14 23:52:34 +00:00
t1 = ctx - > start [ plane - > type ] - plane - > dist ;
t2 = ctx - > end [ plane - > type ] - plane - > dist ;
2010-02-15 23:26:55 +00:00
}
2018-07-14 23:52:34 +00:00
else
{
t1 = DotProduct ( plane - > normal , ctx - > start ) - plane - > dist ;
t2 = DotProduct ( plane - > normal , ctx - > end ) - plane - > dist ;
}
side = t1 < 0 ;
2010-02-15 23:26:55 +00:00
2018-07-14 23:52:34 +00:00
midf = t1 / ( t1 - t2 ) ;
if ( midf < p1f ) midf = p1f ;
if ( midf > p2f ) midf = p2f ;
VectorInterpolate ( ctx - > start , midf , ctx - > end , mid ) ;
2010-02-15 23:26:55 +00:00
2018-07-14 23:52:34 +00:00
rht = Q1BSP_RecursiveHullTrace ( ctx , node - > children [ side ] , p1f , midf , p1 , mid , trace ) ;
if ( rht ! = rht_empty & & ! trace - > allsolid )
return rht ;
rht = Q1BSP_RecursiveHullTrace ( ctx , node - > children [ side ^ 1 ] , midf , p2f , mid , p2 , trace ) ;
if ( rht ! = rht_solid )
return rht ;
2010-02-15 23:26:55 +00:00
2018-07-14 23:52:34 +00:00
if ( side )
2010-02-15 23:26:55 +00:00
{
2018-07-14 23:52:34 +00:00
/*we impacted the back of the node, so flip the plane*/
trace - > plane . dist = - plane - > dist ;
VectorNegate ( plane - > normal , trace - > plane . normal ) ;
midf = ( t1 + DIST_EPSILON ) / ( t1 - t2 ) ;
2010-02-15 23:26:55 +00:00
}
else
{
2018-07-14 23:52:34 +00:00
/*we impacted the front of the node*/
trace - > plane . dist = plane - > dist ;
VectorCopy ( plane - > normal , trace - > plane . normal ) ;
midf = ( t1 - DIST_EPSILON ) / ( t1 - t2 ) ;
2010-02-15 23:26:55 +00:00
}
2018-07-15 23:59:35 +00:00
t1 = DoublePrecisionDotProduct ( trace - > plane . normal , ctx - > start ) - trace - > plane . dist ;
t2 = DoublePrecisionDotProduct ( trace - > plane . normal , ctx - > end ) - trace - > plane . dist ;
2018-07-14 23:52:34 +00:00
midf = ( t1 - DIST_EPSILON ) / ( t1 - t2 ) ;
2010-02-15 23:26:55 +00:00
2018-07-14 23:52:34 +00:00
midf = CLAMP ( 0 , midf , 1 ) ;
2010-02-15 23:26:55 +00:00
trace - > fraction = midf ;
VectorCopy ( mid , trace - > endpos ) ;
2018-07-14 23:52:34 +00:00
VectorInterpolate ( ctx - > start , midf , ctx - > end , trace - > endpos ) ;
2010-02-15 23:26:55 +00:00
2018-07-14 23:52:34 +00:00
return rht_impact ;
2010-02-15 23:26:55 +00:00
}
2021-09-25 01:18:23 +00:00
qboolean SV_SlowRecursiveHullCheck ( hull_t * hull , int num , float p1f , float p2f , vec3_t p1 , vec3_t p2 , trace_t * trace )
{
mclipnode_t * node ; //johnfitz -- was dclipnode_t
mplane_t * plane ;
float t1 , t2 ;
float frac ;
int i ;
vec3_t mid ;
int side ;
float midf ;
// check for empty
if ( num < 0 )
{
if ( num ! = CONTENTS_SOLID )
{
trace - > allsolid = false ;
if ( num = = CONTENTS_EMPTY )
trace - > inopen = true ;
else
trace - > inwater = true ;
}
else
trace - > startsolid = true ;
return true ; // empty
}
if ( num < hull - > firstclipnode | | num > hull - > lastclipnode )
Sys_Error ( " SV_RecursiveHullCheck: bad node number " ) ;
//
// find the point distances
//
node = hull - > clipnodes + num ;
plane = hull - > planes + node - > planenum ;
if ( plane - > type < 3 )
{
t1 = p1 [ plane - > type ] - plane - > dist ;
t2 = p2 [ plane - > type ] - plane - > dist ;
}
else
{
t1 = DoublePrecisionDotProduct ( plane - > normal , p1 ) - plane - > dist ;
t2 = DoublePrecisionDotProduct ( plane - > normal , p2 ) - plane - > dist ;
}
# if 1
if ( t1 > = 0 & & t2 > = 0 )
return SV_SlowRecursiveHullCheck ( hull , node - > children [ 0 ] , p1f , p2f , p1 , p2 , trace ) ;
if ( t1 < 0 & & t2 < 0 )
return SV_SlowRecursiveHullCheck ( hull , node - > children [ 1 ] , p1f , p2f , p1 , p2 , trace ) ;
# else
if ( ( t1 > = DIST_EPSILON & & t2 > = DIST_EPSILON ) | | ( t2 > t1 & & t1 > = 0 ) )
return SV_SlowRecursiveHullCheck ( hull , node - > children [ 0 ] , p1f , p2f , p1 , p2 , trace ) ;
if ( ( t1 < = - DIST_EPSILON & & t2 < = - DIST_EPSILON ) | | ( t2 < t1 & & t1 < = 0 ) )
return SV_SlowRecursiveHullCheck ( hull , node - > children [ 1 ] , p1f , p2f , p1 , p2 , trace ) ;
# endif
// put the crosspoint DIST_EPSILON pixels on the near side
if ( t1 < 0 )
frac = ( t1 + DIST_EPSILON ) / ( t1 - t2 ) ;
else
frac = ( t1 - DIST_EPSILON ) / ( t1 - t2 ) ;
if ( frac < 0 )
frac = 0 ;
if ( frac > 1 )
frac = 1 ;
midf = p1f + ( p2f - p1f ) * frac ;
for ( i = 0 ; i < 3 ; i + + )
mid [ i ] = p1 [ i ] + frac * ( p2 [ i ] - p1 [ i ] ) ;
side = ( t1 < 0 ) ;
// move up to the node
if ( ! SV_SlowRecursiveHullCheck ( hull , node - > children [ side ] , p1f , midf , p1 , mid , trace ) )
return false ;
# ifdef PARANOID
if ( SV_HullPointContents ( sv_hullmodel , mid , node - > children [ side ] )
= = CONTENTS_SOLID )
{
Con_Printf ( " mid PointInHullSolid \n " ) ;
return false ;
}
# endif
if ( SV_HullPointContents ( hull , node - > children [ side ^ 1 ] , mid )
! = CONTENTS_SOLID )
// go past the node
return SV_SlowRecursiveHullCheck ( hull , node - > children [ side ^ 1 ] , midf , p2f , mid , p2 , trace ) ;
if ( trace - > allsolid )
return false ; // never got out of the solid area
//==================
// the other side of the node is solid, this is the impact point
//==================
if ( ! side )
{
VectorCopy ( plane - > normal , trace - > plane . normal ) ;
trace - > plane . dist = plane - > dist ;
}
else
{
VectorSubtract ( vec3_origin , plane - > normal , trace - > plane . normal ) ;
trace - > plane . dist = - plane - > dist ;
}
while ( SV_HullPointContents ( hull , hull - > firstclipnode , mid )
= = CONTENTS_SOLID )
{ // shouldn't really happen, but does occasionally
frac - = 0.1 ;
if ( frac < 0 )
{
trace - > fraction = midf ;
VectorCopy ( mid , trace - > endpos ) ;
Con_DPrintf ( " backup past 0 \n " ) ;
return false ;
}
midf = p1f + ( p2f - p1f ) * frac ;
for ( i = 0 ; i < 3 ; i + + )
mid [ i ] = p1 [ i ] + frac * ( p2 [ i ] - p1 [ i ] ) ;
}
trace - > fraction = midf ;
VectorCopy ( mid , trace - > endpos ) ;
return false ;
}
2018-07-14 23:52:34 +00:00
/*
= = = = = = = = = = = = = = = = = =
SV_RecursiveHullCheck
Decides if its a simple point test , or does a slightly more expensive check .
= = = = = = = = = = = = = = = = = =
*/
2021-03-06 06:04:42 +00:00
qboolean SV_RecursiveHullCheck ( hull_t * hull , vec3_t p1 , vec3_t p2 , trace_t * trace , unsigned int hitcontents )
2018-07-14 23:52:34 +00:00
{
2021-09-25 01:18:23 +00:00
if ( ! pr_checkextension . value )
return SV_SlowRecursiveHullCheck ( hull , hull - > firstclipnode , 0 , 1 , p1 , p2 , trace ) ;
else if ( p1 [ 0 ] = = p2 [ 0 ] & & p1 [ 1 ] = = p2 [ 1 ] & & p1 [ 2 ] = = p2 [ 2 ] )
2018-07-14 23:52:34 +00:00
{
/*points cannot cross planes, so do it faster*/
2021-03-06 06:04:42 +00:00
int c = SV_HullPointContents ( hull , hull - > firstclipnode , p1 ) ;
2019-09-13 17:51:16 +00:00
trace - > contents = c ;
2021-03-06 06:04:42 +00:00
if ( hitcontents & CONTENTMASK_FROMQ1 ( c ) )
2018-07-14 23:52:34 +00:00
trace - > startsolid = true ;
2021-03-06 06:04:42 +00:00
else
{
2018-07-14 23:52:34 +00:00
trace - > allsolid = false ;
2021-03-06 06:04:42 +00:00
if ( c = = CONTENTS_EMPTY )
trace - > inopen = true ;
else if ( c ! = CONTENTS_SOLID )
trace - > inwater = true ;
2018-07-14 23:52:34 +00:00
}
return true ;
}
else
{
struct rhtctx_s ctx ;
VectorCopy ( p1 , ctx . start ) ;
VectorCopy ( p2 , ctx . end ) ;
ctx . clipnodes = hull - > clipnodes ;
ctx . planes = hull - > planes ;
2021-03-06 06:04:42 +00:00
ctx . hitcontents = hitcontents ;
2021-09-25 01:18:23 +00:00
return Q1BSP_RecursiveHullTrace ( & ctx , hull - > firstclipnode , 0 , 1 , p1 , p2 , trace ) ! = rht_impact ;
2018-07-14 23:52:34 +00:00
}
}
2010-02-15 23:26:55 +00:00
/*
= = = = = = = = = = = = = = = = = =
SV_ClipMoveToEntity
Handles selection or creation of a clipping hull , and offseting ( and
eventually rotation ) of the end points
= = = = = = = = = = = = = = = = = =
*/
2021-03-06 04:51:40 +00:00
trace_t SV_ClipMoveToEntity ( edict_t * ent , vec3_t start , vec3_t mins , vec3_t maxs , vec3_t end , unsigned int hitcontents )
2010-02-15 23:26:55 +00:00
{
trace_t trace ;
vec3_t offset ;
vec3_t start_l , end_l ;
hull_t * hull ;
// fill in a default trace
memset ( & trace , 0 , sizeof ( trace_t ) ) ;
trace . fraction = 1 ;
trace . allsolid = true ;
VectorCopy ( end , trace . endpos ) ;
// get the clipping hull
hull = SV_HullForEntity ( ent , mins , maxs , offset ) ;
VectorSubtract ( start , offset , start_l ) ;
VectorSubtract ( end , offset , end_l ) ;
// trace a line through the apropriate clipping hull
2022-08-23 09:10:17 +00:00
if ( ( ent - > v . solid = = SOLID_BSP | | ent - > v . solid = = SOLID_EXT_BSPTRIGGER ) & & ( ent - > v . angles [ 0 ] | | ent - > v . angles [ 1 ] | | ent - > v . angles [ 2 ] ) & & qcvm - > edicts ! = ent ) //don't rotate the world entity's collisions (its not networked, and some maps are buggy, resulting in screwed collisions)
2020-04-06 23:56:15 +00:00
{
2022-08-23 09:10:17 +00:00
if ( qcvm - > rotatingbmodel )
{
2020-04-06 23:56:15 +00:00
# define DotProductTranspose(v,m,a) ((v)[0]*(m)[0][a] + (v)[1]*(m)[1][a] + (v)[2]*(m)[2][a])
2022-08-23 09:10:17 +00:00
vec3_t axis [ 3 ] , start_r , end_r , tmp ;
AngleVectors ( ent - > v . angles , axis [ 0 ] , axis [ 1 ] , axis [ 2 ] ) ;
VectorInverse ( axis [ 1 ] ) ;
start_r [ 0 ] = DotProduct ( start_l , axis [ 0 ] ) ;
start_r [ 1 ] = DotProduct ( start_l , axis [ 1 ] ) ;
start_r [ 2 ] = DotProduct ( start_l , axis [ 2 ] ) ;
end_r [ 0 ] = DotProduct ( end_l , axis [ 0 ] ) ;
end_r [ 1 ] = DotProduct ( end_l , axis [ 1 ] ) ;
end_r [ 2 ] = DotProduct ( end_l , axis [ 2 ] ) ;
SV_RecursiveHullCheck ( hull , start_r , end_r , & trace , hitcontents ) ;
VectorCopy ( trace . endpos , tmp ) ;
trace . endpos [ 0 ] = DotProductTranspose ( tmp , axis , 0 ) ;
trace . endpos [ 1 ] = DotProductTranspose ( tmp , axis , 1 ) ;
trace . endpos [ 2 ] = DotProductTranspose ( tmp , axis , 2 ) ;
VectorCopy ( trace . plane . normal , tmp ) ;
trace . plane . normal [ 0 ] = DotProductTranspose ( tmp , axis , 0 ) ;
trace . plane . normal [ 1 ] = DotProductTranspose ( tmp , axis , 1 ) ;
trace . plane . normal [ 2 ] = DotProductTranspose ( tmp , axis , 2 ) ;
}
else
{
if ( ! qcvm - > warned_rotatingbmodel )
{
Con_Warning ( " %s( \" %s \" ) has angles set, but DP_SV_ROTATINGBMODEL is not enabled \n " , ( ent - > v . solid = = SOLID_EXT_BSPTRIGGER ) ? " SOLID_BSPTRIGGER " : " SOLID_BSP " , PR_GetString ( ent - > v . classname ) ) ;
qcvm - > warned_rotatingbmodel = true ;
}
SV_RecursiveHullCheck ( hull , start_l , end_l , & trace , hitcontents ) ;
}
2020-04-06 23:56:15 +00:00
}
else
2021-03-06 06:04:42 +00:00
SV_RecursiveHullCheck ( hull , start_l , end_l , & trace , hitcontents ) ;
2010-02-15 23:26:55 +00:00
// fix trace up by the offset
if ( trace . fraction ! = 1 )
VectorAdd ( trace . endpos , offset , trace . endpos ) ;
// did we clip the move?
if ( trace . fraction < 1 | | trace . startsolid )
trace . ent = ent ;
return trace ;
}
//===========================================================================
/*
= = = = = = = = = = = = = = = = = = = =
SV_ClipToLinks
Mins and maxs enclose the entire area swept by the move
= = = = = = = = = = = = = = = = = = = =
*/
2020-09-04 10:58:21 +00:00
static void SV_ClipToLinks ( areanode_t * node , moveclip_t * clip )
2010-02-15 23:26:55 +00:00
{
link_t * l , * next ;
edict_t * touch ;
trace_t trace ;
// touch linked edicts
for ( l = node - > solid_edicts . next ; l ! = & node - > solid_edicts ; l = next )
{
next = l - > next ;
touch = EDICT_FROM_AREA ( l ) ;
if ( touch - > v . solid = = SOLID_NOT )
continue ;
if ( touch = = clip - > passedict )
continue ;
2021-09-08 01:44:57 +00:00
if ( touch - > v . solid = = SOLID_TRIGGER | | touch - > v . solid = = SOLID_EXT_BSPTRIGGER )
2010-02-15 23:26:55 +00:00
Sys_Error ( " Trigger in clipping list " ) ;
if ( clip - > type = = MOVE_NOMONSTERS & & touch - > v . solid ! = SOLID_BSP )
continue ;
if ( clip - > boxmins [ 0 ] > touch - > v . absmax [ 0 ]
| | clip - > boxmins [ 1 ] > touch - > v . absmax [ 1 ]
| | clip - > boxmins [ 2 ] > touch - > v . absmax [ 2 ]
| | clip - > boxmaxs [ 0 ] < touch - > v . absmin [ 0 ]
| | clip - > boxmaxs [ 1 ] < touch - > v . absmin [ 1 ]
| | clip - > boxmaxs [ 2 ] < touch - > v . absmin [ 2 ] )
continue ;
if ( clip - > passedict & & clip - > passedict - > v . size [ 0 ] & & ! touch - > v . size [ 0 ] )
continue ; // points never interact
2017-09-17 02:12:53 +00:00
if ( pr_checkextension . value )
{
//corpses are nonsolid to slidebox
if ( clip - > passedict - > v . solid = = SOLID_SLIDEBOX & & touch - > v . solid = = SOLID_EXT_CORPSE )
continue ;
//corpses ignore slidebox or corpses
if ( clip - > passedict - > v . solid = = SOLID_EXT_CORPSE & & ( touch - > v . solid = = SOLID_SLIDEBOX | | touch - > v . solid = = SOLID_EXT_CORPSE ) )
continue ;
}
2010-02-15 23:26:55 +00:00
// might intersect, so do an exact clip
if ( clip - > trace . allsolid )
return ;
if ( clip - > passedict )
{
if ( PROG_TO_EDICT ( touch - > v . owner ) = = clip - > passedict )
continue ; // don't clip against own missiles
if ( PROG_TO_EDICT ( clip - > passedict - > v . owner ) = = touch )
continue ; // don't clip against owner
}
2021-03-06 04:51:40 +00:00
if ( touch - > v . skin < 0 )
{
if ( ! ( clip - > hitcontents & ( 1 < < - ( int ) touch - > v . skin ) ) )
continue ; //not solid, don't bother trying to clip.
if ( ( int ) touch - > v . flags & FL_MONSTER )
trace = SV_ClipMoveToEntity ( touch , clip - > start , clip - > mins2 , clip - > maxs2 , clip - > end , ~ ( 1 < < - CONTENTS_EMPTY ) ) ;
else
trace = SV_ClipMoveToEntity ( touch , clip - > start , clip - > mins , clip - > maxs , clip - > end , ~ ( 1 < < - CONTENTS_EMPTY ) ) ;
if ( trace . contents ! = CONTENTS_EMPTY )
trace . contents = touch - > v . skin ;
}
2010-02-15 23:26:55 +00:00
else
2021-03-06 04:51:40 +00:00
{
if ( ( int ) touch - > v . flags & FL_MONSTER )
trace = SV_ClipMoveToEntity ( touch , clip - > start , clip - > mins2 , clip - > maxs2 , clip - > end , clip - > hitcontents ) ;
else
trace = SV_ClipMoveToEntity ( touch , clip - > start , clip - > mins , clip - > maxs , clip - > end , clip - > hitcontents ) ;
}
2019-09-13 17:51:16 +00:00
2010-02-15 23:26:55 +00:00
if ( trace . allsolid | | trace . startsolid | |
trace . fraction < clip - > trace . fraction )
{
trace . ent = touch ;
if ( clip - > trace . startsolid )
{
clip - > trace = trace ;
clip - > trace . startsolid = true ;
}
else
clip - > trace = trace ;
}
else if ( trace . startsolid )
clip - > trace . startsolid = true ;
}
// recurse down both sides
if ( node - > axis = = - 1 )
return ;
if ( clip - > boxmaxs [ node - > axis ] > node - > dist )
SV_ClipToLinks ( node - > children [ 0 ] , clip ) ;
if ( clip - > boxmins [ node - > axis ] < node - > dist )
SV_ClipToLinks ( node - > children [ 1 ] , clip ) ;
}
2020-09-04 10:58:21 +00:00
static void World_ClipToNetwork ( moveclip_t * clip )
{
entity_t * touch ;
trace_t trace ;
int i ;
for ( i = 1 , touch = cl . entities + 1 ; i < cl . num_entities ; i + + , touch + + )
{
if ( ! touch - > model )
continue ;
if ( touch - > netstate . solidsize = = ES_SOLID_NOT )
continue ;
// if (touch == clip->passedict)
// continue;
if ( clip - > type = = MOVE_NOMONSTERS & & touch - > netstate . solidsize ! = ES_SOLID_BSP )
continue ;
/* if (clip->boxmins[0] > touch->v.absmax[0]
| | clip - > boxmins [ 1 ] > touch - > v . absmax [ 1 ]
| | clip - > boxmins [ 2 ] > touch - > v . absmax [ 2 ]
| | clip - > boxmaxs [ 0 ] < touch - > v . absmin [ 0 ]
| | clip - > boxmaxs [ 1 ] < touch - > v . absmin [ 1 ]
| | clip - > boxmaxs [ 2 ] < touch - > v . absmin [ 2 ] )
continue ;
*/
// might intersect, so do an exact clip
if ( clip - > trace . allsolid )
return ;
/* if (clip->passedict)
{
if ( PROG_TO_EDICT ( touch - > v . owner ) = = clip - > passedict )
continue ; // don't clip against own missiles
if ( PROG_TO_EDICT ( clip - > passedict - > v . owner ) = = touch )
continue ; // don't clip against owner
}
*/
//:: trace = SV_ClipMoveToEntity (touch, clip->start, clip->mins, clip->maxs, clip->end);
{
vec3_t offset ;
vec3_t start_l , end_l ;
hull_t * hull ;
// fill in a default trace
memset ( & trace , 0 , sizeof ( trace_t ) ) ;
trace . fraction = 1 ;
trace . allsolid = true ;
VectorCopy ( clip - > end , trace . endpos ) ;
// get the clipping hull
//:: hull = SV_HullForEntity (ent, clip->mins, clip->maxs, offset);
{
vec3_t size ;
if ( touch - > netstate . solidsize = = ES_SOLID_BSP & & touch - > model & & touch - > model - > type = = mod_brush )
{ // explicit hulls in the BSP model
VectorSubtract ( clip - > maxs , clip - > mins , size ) ;
if ( size [ 0 ] < 3 )
hull = & touch - > model - > hulls [ 0 ] ;
else if ( size [ 0 ] < = 32 )
hull = & touch - > model - > hulls [ 1 ] ;
else
hull = & touch - > model - > hulls [ 2 ] ;
// calculate an offset value to center the origin
VectorSubtract ( hull - > clip_mins , clip - > mins , offset ) ;
VectorAdd ( offset , touch - > origin , offset ) ;
}
else
{ // create a temp hull from bounding box sizes
vec3_t hullmins , hullmaxs ;
vec3_t touch_mins , touch_maxs ;
touch_maxs [ 0 ] = touch_maxs [ 1 ] = touch - > netstate . solidsize & 255 ;
touch_mins [ 0 ] = touch_mins [ 1 ] = - touch_maxs [ 0 ] ;
2023-07-22 16:40:33 +00:00
touch_mins [ 2 ] = - ( int ) ( ( touch - > netstate . solidsize > > 8 ) & 255 ) ;
touch_maxs [ 2 ] = ( int ) ( ( touch - > netstate . solidsize > > 16 ) & 65535 ) - 32768 ;
2020-09-04 10:58:21 +00:00
VectorSubtract ( touch_mins , clip - > maxs , hullmins ) ;
VectorSubtract ( touch_maxs , clip - > mins , hullmaxs ) ;
hull = SV_HullForBox ( hullmins , hullmaxs ) ;
VectorCopy ( touch - > origin , offset ) ;
}
}
VectorSubtract ( clip - > start , offset , start_l ) ;
VectorSubtract ( clip - > end , offset , end_l ) ;
// trace a line through the apropriate clipping hull
2022-08-23 09:10:17 +00:00
if ( touch - > netstate . solidsize = = ES_SOLID_BSP & & ( touch - > angles [ 0 ] | | touch - > angles [ 1 ] | | touch - > angles [ 2 ] ) & & qcvm - > rotatingbmodel ) //don't rotate the world entity's collisions (its not networked, and some maps are buggy, resulting in screwed collisions)
2020-09-04 10:58:21 +00:00
{
# define DotProductTranspose(v,m,a) ((v)[0]*(m)[0][a] + (v)[1]*(m)[1][a] + (v)[2]*(m)[2][a])
vec3_t axis [ 3 ] , start_r , end_r , tmp ;
AngleVectors ( touch - > angles , axis [ 0 ] , axis [ 1 ] , axis [ 2 ] ) ;
VectorInverse ( axis [ 1 ] ) ;
start_r [ 0 ] = DotProduct ( start_l , axis [ 0 ] ) ;
start_r [ 1 ] = DotProduct ( start_l , axis [ 1 ] ) ;
start_r [ 2 ] = DotProduct ( start_l , axis [ 2 ] ) ;
end_r [ 0 ] = DotProduct ( end_l , axis [ 0 ] ) ;
end_r [ 1 ] = DotProduct ( end_l , axis [ 1 ] ) ;
end_r [ 2 ] = DotProduct ( end_l , axis [ 2 ] ) ;
2021-03-06 06:04:42 +00:00
SV_RecursiveHullCheck ( hull , start_r , end_r , & trace , clip - > hitcontents ) ;
2020-09-04 10:58:21 +00:00
VectorCopy ( trace . endpos , tmp ) ;
trace . endpos [ 0 ] = DotProductTranspose ( tmp , axis , 0 ) ;
trace . endpos [ 1 ] = DotProductTranspose ( tmp , axis , 1 ) ;
trace . endpos [ 2 ] = DotProductTranspose ( tmp , axis , 2 ) ;
VectorCopy ( trace . plane . normal , tmp ) ;
trace . plane . normal [ 0 ] = DotProductTranspose ( tmp , axis , 0 ) ;
trace . plane . normal [ 1 ] = DotProductTranspose ( tmp , axis , 1 ) ;
trace . plane . normal [ 2 ] = DotProductTranspose ( tmp , axis , 2 ) ;
}
else
2021-03-06 06:04:42 +00:00
SV_RecursiveHullCheck ( hull , start_l , end_l , & trace , clip - > hitcontents ) ;
2020-09-04 10:58:21 +00:00
// fix trace up by the offset
if ( trace . fraction ! = 1 )
VectorAdd ( trace . endpos , offset , trace . endpos ) ;
// did we clip the move?
if ( trace . fraction < 1 | | trace . startsolid )
trace . ent = qcvm - > edicts ;
}
if ( trace . contents = = CONTENTS_SOLID & & touch - > skinnum < 0 )
trace . contents = touch - > skinnum ;
if ( ! ( ( 1 < < ( - trace . contents ) ) & clip - > hitcontents ) )
continue ;
if ( trace . allsolid | | trace . startsolid | |
trace . fraction < clip - > trace . fraction )
{
trace . ent = qcvm - > edicts ; //no real way to return entity number.
if ( clip - > trace . startsolid )
{
clip - > trace = trace ;
clip - > trace . startsolid = true ;
}
else
clip - > trace = trace ;
}
else if ( trace . startsolid )
clip - > trace . startsolid = true ;
}
}
2010-02-15 23:26:55 +00:00
/*
= = = = = = = = = = = = = = = = = =
SV_MoveBounds
= = = = = = = = = = = = = = = = = =
*/
void SV_MoveBounds ( vec3_t start , vec3_t mins , vec3_t maxs , vec3_t end , vec3_t boxmins , vec3_t boxmaxs )
{
#if 0
// debug to test against everything
boxmins [ 0 ] = boxmins [ 1 ] = boxmins [ 2 ] = - 9999 ;
boxmaxs [ 0 ] = boxmaxs [ 1 ] = boxmaxs [ 2 ] = 9999 ;
# else
int i ;
for ( i = 0 ; i < 3 ; i + + )
{
if ( end [ i ] > start [ i ] )
{
boxmins [ i ] = start [ i ] + mins [ i ] - 1 ;
boxmaxs [ i ] = end [ i ] + maxs [ i ] + 1 ;
}
else
{
boxmins [ i ] = end [ i ] + mins [ i ] - 1 ;
boxmaxs [ i ] = start [ i ] + maxs [ i ] + 1 ;
}
}
# endif
}
/*
= = = = = = = = = = = = = = = = = =
SV_Move
= = = = = = = = = = = = = = = = = =
*/
trace_t SV_Move ( vec3_t start , vec3_t mins , vec3_t maxs , vec3_t end , int type , edict_t * passedict )
{
moveclip_t clip ;
int i ;
memset ( & clip , 0 , sizeof ( moveclip_t ) ) ;
2021-03-06 04:51:40 +00:00
if ( type & MOVE_HITALLCONTENTS )
2021-11-12 04:05:50 +00:00
clip . hitcontents = ~ CONTENTMASK_FROMQ1 ( CONTENTS_EMPTY ) ;
2021-03-06 04:51:40 +00:00
else
clip . hitcontents = CONTENTMASK_ANYSOLID ;
2010-02-15 23:26:55 +00:00
// clip to world
2021-03-06 04:51:40 +00:00
clip . trace = SV_ClipMoveToEntity ( qcvm - > edicts , start , mins , maxs , end , clip . hitcontents ) ;
2010-02-15 23:26:55 +00:00
clip . start = start ;
clip . end = end ;
clip . mins = mins ;
clip . maxs = maxs ;
2019-09-13 17:51:16 +00:00
clip . type = type & 3 ;
2010-02-15 23:26:55 +00:00
clip . passedict = passedict ;
if ( type = = MOVE_MISSILE )
{
for ( i = 0 ; i < 3 ; i + + )
{
clip . mins2 [ i ] = - 15 ;
clip . maxs2 [ i ] = 15 ;
}
}
else
{
VectorCopy ( mins , clip . mins2 ) ;
VectorCopy ( maxs , clip . maxs2 ) ;
}
// create the bounding box of the entire move
SV_MoveBounds ( start , clip . mins2 , clip . maxs2 , end , clip . boxmins , clip . boxmaxs ) ;
// clip to entities
2018-05-01 00:35:14 +00:00
SV_ClipToLinks ( qcvm - > areanodes , & clip ) ;
2010-02-15 23:26:55 +00:00
2020-09-04 10:58:21 +00:00
if ( qcvm = = & cl . qcvm )
World_ClipToNetwork ( & clip ) ;
2010-02-15 23:26:55 +00:00
return clip . trace ;
}