/* * 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; }
void G_SplashFrac4D( int entNum, vec3_t hitpoint, float maxradius, vec3_t pushdir, float *kickFrac, float *dmgFrac, int timeDelta ) { c4clipedict_t *clipEnt; clipEnt = GClip_GetClipEdictForDeltaTime( entNum, timeDelta ); G_SplashFrac( clipEnt->s.origin, clipEnt->r.mins, clipEnt->r.maxs, hitpoint, maxradius, pushdir, kickFrac, dmgFrac ); }
/* * GClip_FindBoxInRadius * Returns entities that have their boxes within a spherical area */ edict_t *GClip_FindBoxInRadius4D( edict_t *from, vec3_t org, float rad, int timeDelta ) { int i, j; c4clipedict_t *check; vec3_t mins, maxs; int fromNum; if( !from ) from = world; fromNum = ENTNUM( from ) + 1; for( i = fromNum; i < game.numentities; i++ ) { if( !game.edicts[i].r.inuse ) continue; check = GClip_GetClipEdictForDeltaTime( i, timeDelta ); if( !check->r.inuse ) continue; if( check->r.solid == SOLID_NOT ) continue; // make absolute mins and maxs for( j = 0; j < 3; j++ ) { mins[j] = check->s.origin[j] + check->r.mins[j]; maxs[j] = check->s.origin[j] + check->r.maxs[j]; } if( !BoundsAndSphereIntersect( mins, maxs, org, rad ) ) continue; return &game.edicts[i]; // return realtime entity } return NULL; }
/* * 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; } }
void G_SplashFrac4D( int entNum, vec3_t hitpoint, float maxradius, vec3_t pushdir, float *kickFrac, float *dmgFrac, int timeDelta ) { c4clipedict_t *clipEnt; clipEnt = GClip_GetClipEdictForDeltaTime( entNum, timeDelta ); // racesow - weqo rs_SplashFrac( clipEnt->s.origin, clipEnt->r.mins, clipEnt->r.maxs, hitpoint, maxradius, pushdir, kickFrac, dmgFrac ); // to use default settings: // G_SplashFrac( clipEnt->s.origin, clipEnt->r.mins, clipEnt->r.maxs, hitpoint, maxradius, pushdir, kickFrac, dmgFrac ); // !racesow }
entity_state_t *G_GetEntityStateForDeltaTime( int entNum, int deltaTime ) { c4clipedict_t *clipEnt; if( entNum == -1 ) return NULL; assert( entNum >= 0 && entNum < MAX_EDICTS ); clipEnt = GClip_GetClipEdictForDeltaTime( entNum, deltaTime ); return &clipEnt->s; }
/* * GClip_AreaEdicts * fills in a table of edict ids with edicts that have bounding boxes * that intersect the given area. It is possible for a non-axial bmodel * to be returned that doesn't actually intersect the area on an exact * test. * returns the number of pointers filled in * ??? does this always return the world? */ static int GClip_AreaEdicts( vec3_t mins, vec3_t maxs, int *list, int maxcount, int areatype, int timeDelta ) { link_t *l, *start; c4clipedict_t *clipEnt; int stackdepth = 0, count = 0; areanode_t *localstack[AREA_NODES], *node = sv_areanodes; while( 1 ) { // touch linked edicts if( areatype == AREA_SOLID ) start = &node->solid_edicts; else start = &node->trigger_edicts; for( l = start->next; l != start; l = l->next ) { clipEnt = GClip_GetClipEdictForDeltaTime( l->entNum, timeDelta ); if( clipEnt->r.solid == SOLID_NOT ) continue; // deactivated if( !BoundsIntersect( clipEnt->r.absmin, clipEnt->r.absmax, mins, maxs ) ) continue; // not touching if( count == maxcount ) { G_Printf( "G_AreaEdicts: MAXCOUNT\n" ); return count; } list[count++] = l->entNum; } if( node->axis == -1 ) goto checkstack; // terminal node // recurse down both sides if( maxs[node->axis] > node->dist ) { if( mins[node->axis] < node->dist ) { localstack[stackdepth++] = node->children[0]; node = node->children[1]; continue; } node = node->children[0]; continue; } if( mins[node->axis] < node->dist ) { node = node->children[1]; continue; } checkstack: if( !stackdepth ) return count; node = localstack[--stackdepth]; } return count; }
/* * GClip_EntitiesInBox_AreaGrid */ static int GClip_EntitiesInBox_AreaGrid( areagrid_t *areagrid, const vec3_t mins, const vec3_t maxs, int *list, int maxcount, int areatype, int timeDelta ) { int numlist; link_t *grid; link_t *l; c4clipedict_t *clipEnt; vec3_t paddedmins, paddedmaxs; int igrid[3], igridmins[3], igridmaxs[3]; // LordHavoc: discovered this actually causes its own bugs (dm6 teleporters // being too close to info_teleport_destination) //VectorSet( paddedmins, mins[0] - 1.0f, mins[1] - 1.0f, mins[2] - 1.0f ); //VectorSet( paddedmaxs, maxs[0] + 1.0f, maxs[1] + 1.0f, maxs[2] + 1.0f ); VectorCopy( mins, paddedmins ); VectorCopy( maxs, paddedmaxs ); // FIXME: if areagrid_marknumber wraps, all entities need their // ent->priv.server->areagridmarknumber reset areagrid->marknumber++; igridmins[0] = (int) floor( (paddedmins[0] + areagrid->bias[0]) * areagrid->scale[0] ); igridmins[1] = (int) floor( (paddedmins[1] + areagrid->bias[1]) * areagrid->scale[1] ); //igridmins[2] = (int) ( (paddedmins[2] + areagrid->bias[2]) * areagrid->scale[2] ); igridmaxs[0] = (int) floor( (paddedmaxs[0] + areagrid->bias[0]) * areagrid->scale[0] ) + 1; igridmaxs[1] = (int) floor( (paddedmaxs[1] + areagrid->bias[1]) * areagrid->scale[1] ) + 1; //igridmaxs[2] = (int) ( (paddedmaxs[2] + areagrid->bias[2]) * areagrid->scale[2] ) + 1; igridmins[0] = max( 0, igridmins[0] ); igridmins[1] = max( 0, igridmins[1] ); //igridmins[2] = max( 0, igridmins[2] ); igridmaxs[0] = min( AREA_GRID, igridmaxs[0] ); igridmaxs[1] = min( AREA_GRID, igridmaxs[1] ); //igridmaxs[2] = min( AREA_GRID, igridmaxs[2] ); // paranoid debugging //VectorSet( igridmins, 0, 0, 0 );VectorSet( igridmaxs, AREA_GRID, AREA_GRID, AREA_GRID ); numlist = 0; // add entities not linked into areagrid because they are too big or // outside the grid bounds if( areagrid->outside.next ) { grid = &areagrid->outside; for( l = grid->next; l != grid; l = l->next ) { clipEnt = GClip_GetClipEdictForDeltaTime( l->entNum, timeDelta ); if( areagrid->entmarknumber[l->entNum] == areagrid->marknumber ) { continue; } areagrid->entmarknumber[l->entNum] = areagrid->marknumber; if( !clipEnt->r.inuse ) { continue; // deactivated } if( areatype == AREA_TRIGGERS && clipEnt->r.solid != SOLID_TRIGGER ) { continue; } if( areatype == AREA_SOLID && ( clipEnt->r.solid == SOLID_TRIGGER || clipEnt->r.solid == SOLID_NOT ) ) { continue; } if( BoundsIntersect( paddedmins, paddedmaxs, clipEnt->r.absmin, clipEnt->r.absmax )) { if( numlist < maxcount ) { list[numlist] = l->entNum; } numlist++; } } } // add grid linked entities for( igrid[1] = igridmins[1]; igrid[1] < igridmaxs[1]; igrid[1]++ ) { grid = areagrid->grid + igrid[1] * AREA_GRID + igridmins[0]; for( igrid[0] = igridmins[0]; igrid[0] < igridmaxs[0]; igrid[0]++, grid++ ) { if( !grid->next ) { continue; } for( l = grid->next; l != grid; l = l->next ) { clipEnt = GClip_GetClipEdictForDeltaTime( l->entNum, timeDelta ); if( areagrid->entmarknumber[l->entNum] == areagrid->marknumber ) { continue; } areagrid->entmarknumber[l->entNum] = areagrid->marknumber; if( !clipEnt->r.inuse ) { continue; // deactivated } if( areatype == AREA_TRIGGERS && clipEnt->r.solid != SOLID_TRIGGER ) { continue; } if( areatype == AREA_SOLID && ( clipEnt->r.solid == SOLID_TRIGGER || clipEnt->r.solid == SOLID_NOT ) ) { continue; } if( BoundsIntersect( paddedmins, paddedmaxs, clipEnt->r.absmin, clipEnt->r.absmax )) { if( numlist < maxcount ) { list[numlist] = l->entNum; } numlist++; } } } } return numlist; }