/* * G_PointContents * returns the CONTENTS_* value from the world at the given point. * Quake 2 extends this to also check entities, to allow moving liquids */ static int GClip_PointContents( vec3_t p, int timeDelta ) { c4clipedict_t *clipEnt; int touch[MAX_EDICTS]; int i, num; int contents, c2; struct cmodel_s *cmodel; float *angles; // get base contents from world contents = trap_CM_TransformedPointContents( p, NULL, NULL, NULL ); // or in contents from all the other entities num = GClip_AreaEdicts( p, p, touch, MAX_EDICTS, AREA_SOLID, timeDelta ); for( i = 0; i < num; i++ ) { clipEnt = GClip_GetClipEdictForDeltaTime( touch[i], timeDelta ); // might intersect, so do an exact clip cmodel = GClip_CollisionModelForEntity( &clipEnt->s, &clipEnt->r ); if( !ISBRUSHMODEL( clipEnt->s.modelindex ) ) angles = vec3_origin; // boxes don't rotate else angles = clipEnt->s.angles; c2 = trap_CM_TransformedPointContents( p, cmodel, clipEnt->s.origin, clipEnt->s.angles ); contents |= c2; } return contents; }
/* * GClip_FindBoxInRadius * Returns entities that have their boxes within a spherical area */ int GClip_FindBoxInRadius4D( vec3_t org, float rad, int *list, int maxcount, int timeDelta ) { int i, num; int listnum; edict_t *check; vec3_t mins, maxs; float rad_ = rad * 1.42; int touch[MAX_EDICTS]; VectorSet( mins, org[0] - (rad_ + 1), org[1] - (rad_ + 1), org[2] - (rad_ + 1) ); VectorSet( maxs, org[0] + (rad_ + 1), org[1] + (rad_ + 1), org[2] + (rad_ + 1) ); listnum = 0; num = GClip_AreaEdicts( mins, maxs, touch, MAX_EDICTS, AREA_ALL, timeDelta ); for( i = 0; i < num; i++ ) { check = EDICT_NUM( touch[i] ); // make absolute mins and maxs if( !BoundsAndSphereIntersect( check->r.absmin, check->r.absmax, org, rad ) ) continue; if( check->s.solid == SOLID_NOT ) continue; if( listnum < maxcount ) { list[listnum] = touch[i]; } listnum++; } return listnum; }
/* * GClip_ClipMoveToEntities */ /*static*/ void GClip_ClipMoveToEntities( moveclip_t *clip, int timeDelta ) { int i, num; c4clipedict_t *touch; int touchlist[MAX_EDICTS]; trace_t trace; struct cmodel_s *cmodel; float *angles; num = GClip_AreaEdicts( clip->boxmins, clip->boxmaxs, touchlist, MAX_EDICTS, AREA_SOLID, timeDelta ); // be careful, it is possible to have an entity in this // list removed before we get to it (killtriggered) for( i = 0; i < num; i++ ) { touch = GClip_GetClipEdictForDeltaTime( touchlist[i], timeDelta ); if( clip->passent >= 0 ) { // when they are offseted in time, they can be a different pointer but be the same entity if( touch->s.number == clip->passent ) continue; if( touch->r.owner && ( touch->r.owner->s.number == clip->passent ) ) continue; if( game.edicts[clip->passent].r.owner && ( game.edicts[clip->passent].r.owner->s.number == touch->s.number ) ) continue; // wsw : jal : never clipmove against SVF_PROJECTILE entities if( touch->r.svflags & SVF_PROJECTILE ) continue; } if( ( touch->r.svflags & SVF_CORPSE ) && !( clip->contentmask & CONTENTS_CORPSE ) ) continue; // might intersect, so do an exact clip cmodel = GClip_CollisionModelForEntity( &touch->s, &touch->r ); if( ISBRUSHMODEL( touch->s.modelindex ) ) angles = touch->s.angles; else angles = vec3_origin; // boxes don't rotate trap_CM_TransformedBoxTrace( &trace, clip->start, clip->end, clip->mins, clip->maxs, cmodel, clip->contentmask, touch->s.origin, angles ); if( trace.allsolid || trace.fraction < clip->trace->fraction ) { trace.ent = touch->s.number; *( clip->trace ) = trace; } else if( trace.startsolid ) clip->trace->startsolid = qtrue; if( clip->trace->allsolid ) return; } }
/* * GClip_TouchTriggers */ void GClip_TouchTriggers( edict_t *ent ) { int i, num; edict_t *hit; int touch[MAX_EDICTS]; vec3_t mins, maxs; // dead things don't activate triggers! if( ent->r.client && G_IsDead( ent ) ) return; VectorAdd( ent->s.origin, ent->r.mins, mins ); VectorAdd( ent->s.origin, ent->r.maxs, maxs ); // FIXME: should be s.origin + mins and s.origin + maxs because of absmin and absmax padding? num = GClip_AreaEdicts( ent->r.absmin, ent->r.absmax, touch, MAX_EDICTS, AREA_TRIGGERS, 0 ); // be careful, it is possible to have an entity in this // list removed before we get to it (killtriggered) for( i = 0; i < num; i++ ) { if( !ent->r.inuse ) break; hit = &game.edicts[touch[i]]; if( !hit->r.inuse ) continue; if( !hit->touch && !hit->asTouchFunc ) continue; if( !hit->item && !GClip_EntityContact( mins, maxs, hit ) ) continue; G_CallTouch( hit, ent, NULL, 0 ); } }
void G_PMoveTouchTriggers( pmove_t *pm ) { int i, num; edict_t *hit; int touch[MAX_EDICTS]; vec3_t mins, maxs; edict_t *ent; if( pm->playerState->POVnum <= 0 || (int)pm->playerState->POVnum > gs.maxclients ) return; ent = game.edicts + pm->playerState->POVnum; if( !ent->r.client || G_IsDead( ent ) ) // dead things don't activate triggers! return; // update the entity with the new position VectorCopy( pm->playerState->pmove.origin, ent->s.origin ); VectorCopy( pm->playerState->pmove.velocity, ent->velocity ); VectorCopy( pm->playerState->viewangles, ent->s.angles ); ent->viewheight = pm->playerState->viewheight; VectorCopy( pm->mins, ent->r.mins ); VectorCopy( pm->maxs, ent->r.maxs ); ent->waterlevel = pm->waterlevel; ent->watertype = pm->watertype; if( pm->groundentity == -1 ) { ent->groundentity = NULL; } else { ent->groundentity = &game.edicts[pm->groundentity]; ent->groundentity_linkcount = ent->groundentity->r.linkcount; } GClip_LinkEntity( ent ); VectorAdd( pm->playerState->pmove.origin, pm->mins, mins ); VectorAdd( pm->playerState->pmove.origin, pm->maxs, maxs ); num = GClip_AreaEdicts( mins, maxs, touch, MAX_EDICTS, AREA_TRIGGERS, 0 ); // be careful, it is possible to have an entity in this // list removed before we get to it (killtriggered) for( i = 0; i < num; i++ ) { if( !ent->r.inuse ) break; hit = &game.edicts[touch[i]]; if( !hit->r.inuse ) continue; if( !hit->touch && !hit->asTouchFunc ) continue; if( !hit->item && !GClip_EntityContact( mins, maxs, hit ) ) continue; G_CallTouch( hit, ent, NULL, 0 ); } }