qboolean AI_ValidateNoEnemyGroupMember( AIGroupInfo_t *group, gentity_t *member ) { if ( !group ) { return qfalse; } vec3_t center; if ( group->commander ) { VectorCopy( group->commander->currentOrigin, center ); } else {//hmm, just pick the first member if ( group->member[0].number < 0 || group->member[0].number >= ENTITYNUM_WORLD ) { return qfalse; } VectorCopy( g_entities[group->member[0].number].currentOrigin, center ); } //FIXME: maybe it should be based on the center of the mass of the group, not the commander? if ( DistanceSquared( center, member->currentOrigin ) > 147456/*384*384*/ ) { return qfalse; } if ( !gi.inPVS( member->currentOrigin, center ) ) {//not within PVS of the group enemy return qfalse; } return qtrue; }
/* ================= S_Base_HearingThroughEntity Also see S_AL_HearingThroughEntity ================= */ static qboolean S_Base_HearingThroughEntity( int entityNum, const vec3_t origin ) { float distanceSq; vec3_t sorigin; if (origin) VectorCopy(origin, sorigin); else VectorCopy(loopSounds[entityNum].origin, sorigin); if( listener_number == entityNum ) { // This is an outrageous hack to detect // whether or not the player is rendering in third person or not. We can't // ask the renderer because the renderer has no notion of entities and we // can't ask cgame since that would involve changing the API and hence mod // compatibility. I don't think there is any way around this, but I'll leave // the FIXME just in case anyone has a bright idea. distanceSq = DistanceSquared( sorigin, listener_origin ); if( distanceSq > THIRD_PERSON_THRESHOLD_SQ ) return qfalse; //we're the player, but third person else return qtrue; //we're the player } else return qfalse; //not the player }
float CVector3::LengthSquared() { float result; Vector3 thisV3 = { X, Y, Z }; DistanceSquared(thisV3, zero, result); return result; }
/* =========== Team_GetLocation Report a location for the player. Uses placed nearby target_location entities ============ */ gentity_t *Team_GetLocation( gentity_t *ent ) { gentity_t *eloc, *best; float bestlen, len; best = NULL; bestlen = 3.0f * 8192.0f * 8192.0f; for ( eloc = level.locationHead; eloc; eloc = eloc->nextPathSegment ) { len = DistanceSquared( ent->r.currentOrigin, eloc->r.currentOrigin ); if ( len > bestlen ) { continue; } if ( !trap_InPVS( ent->r.currentOrigin, eloc->r.currentOrigin ) ) { continue; } bestlen = len; best = eloc; } return best; }
void Rancor_Smash( void ) { int radiusEntNums[128]; int numEnts; const float radius = 128; const float halfRadSquared = ((radius/2)*(radius/2)); const float radiusSquared = (radius*radius); float distSq; int i; vec3_t boltOrg; AddSoundEvent( NPC, NPC->r.currentOrigin, 512, AEL_DANGER, qfalse );//, qtrue ); numEnts = NPC_GetEntsNearBolt( radiusEntNums, radius, NPC->client->renderInfo.handLBolt, boltOrg ); for ( i = 0; i < numEnts; i++ ) { gentity_t *radiusEnt = &g_entities[radiusEntNums[i]]; if ( !radiusEnt->inuse ) { continue; } if ( radiusEnt == NPC ) {//Skip the rancor ent continue; } if ( radiusEnt->client == NULL ) {//must be a client continue; } if ( (radiusEnt->client->ps.eFlags2&EF2_HELD_BY_MONSTER) ) {//can't be one being held continue; } distSq = DistanceSquared( radiusEnt->r.currentOrigin, boltOrg ); if ( distSq <= radiusSquared ) { G_Sound( radiusEnt, CHAN_AUTO, G_SoundIndex( "sound/chars/rancor/swipehit.wav" ) ); if ( distSq < halfRadSquared ) {//close enough to do damage, too G_Damage( radiusEnt, NPC, NPC, vec3_origin, radiusEnt->r.currentOrigin, Q_irand( 10, 25 ), DAMAGE_NO_ARMOR|DAMAGE_NO_KNOCKBACK, MOD_MELEE ); } if ( radiusEnt->health > 0 && radiusEnt->client && radiusEnt->client->NPC_class != CLASS_RANCOR && radiusEnt->client->NPC_class != CLASS_ATST ) { if ( distSq < halfRadSquared || radiusEnt->client->ps.groundEntityNum != ENTITYNUM_NONE ) {//within range of my fist or withing ground-shaking range and not in the air G_Knockdown( radiusEnt );//, NPC, vec3_origin, 100, qtrue ); } } } } }
qboolean NAVNEW_ResolveEntityCollision( gentity_t *self, gentity_t *blocker, vec3_t movedir, vec3_t pathDir, qboolean setBlockedInfo ) { vec3_t blocked_dir; float blocked_dist; //Doors are ignored if ( Q_stricmp( blocker->classname, "func_door" ) == 0 ) { vec3_t center; CalcTeamDoorCenter ( blocker, center ); if ( DistanceSquared( self->r.currentOrigin, center ) > MIN_DOOR_BLOCK_DIST_SQR ) return qtrue; } VectorSubtract( blocker->r.currentOrigin, self->r.currentOrigin, blocked_dir ); blocked_dist = VectorNormalize( blocked_dir ); //First, attempt to walk around the blocker or shove him out of the way if ( NAVNEW_Bypass( self, blocker, blocked_dir, blocked_dist, movedir, setBlockedInfo ) ) return qtrue; //Can't get around him... see if I'm blocking him too... if so, I need to just keep moving? if ( NAVNEW_CheckDoubleBlock( self, blocker, blocked_dir ) ) return qtrue; if ( setBlockedInfo ) { //Complain about it if we can NPC_SetBlocked( self, blocker ); } return qfalse; }
SVector2 EvadeBehavior::Update(float deltaTime) { SVector2 returnForce = SVector2(0.0f, 0.0f); if (mPreviousDestination != SVector2(-1.0f, -1.0f)) { SVector2 targetVelocity = (mpAgent->GetDestination() - mPreviousDestination)/deltaTime; float maxSpeed = mpAgent->GetMaxSpeed(); float distFromTarget = Length(mpAgent->GetDestination() - mpAgent->GetPosition()); float expectedTime = distFromTarget/maxSpeed; mTargetDestination = mpAgent->GetDestination() + targetVelocity * expectedTime; // FLEE const float panicDistanceSq = maxSpeed * maxSpeed; if (DistanceSquared(mpAgent->GetPosition(), mpAgent->GetDestination()) > panicDistanceSq) { return SVector2( 0, 0); } SVector2 positionToDestination = mpAgent->GetPosition() - mTargetDestination; SVector2 desiredVelocity = Normalize(positionToDestination) * mpAgent->GetMaxSpeed(); returnForce = desiredVelocity - mpAgent->GetVelocity(); } mPreviousDestination = mpAgent->GetDestination(); return returnForce; }
/* ------------------------- NPC_CheckSightEvents ------------------------- */ static int G_CheckSightEvents( gentity_t *self, int hFOV, int vFOV, float maxSeeDist, int ignoreAlert, qboolean mustHaveOwner, int minAlertLevel ) { int bestEvent = -1; int bestAlert = -1; int bestTime = -1; float dist, radius; maxSeeDist *= maxSeeDist; for ( int i = 0; i < level.numAlertEvents; i++ ) { //are we purposely ignoring this alert? if ( i == ignoreAlert ) continue; //We're only concerned about sounds if ( level.alertEvents[i].type != AET_SIGHT ) continue; //must be at least this noticable if ( level.alertEvents[i].level < minAlertLevel ) continue; //must have an owner? if ( mustHaveOwner && !level.alertEvents[i].owner ) continue; //Must be within range dist = DistanceSquared( level.alertEvents[i].position, self->currentOrigin ); //can't see it if ( dist > maxSeeDist ) continue; radius = level.alertEvents[i].radius * level.alertEvents[i].radius; if ( dist > radius ) continue; //Must be visible if ( InFOV( level.alertEvents[i].position, self, hFOV, vFOV ) == qfalse ) continue; if ( G_ClearLOS( self, level.alertEvents[i].position ) == qfalse ) continue; //FIXME: possibly have the light level at this point affect the // visibility/alert level of this event? Would also // need to take into account how bright the event // itself is. A lightsaber would stand out more // in the dark... maybe pass in a light level that // is added to the actual light level at this position? //See if this one takes precedence over the previous one if ( level.alertEvents[i].level >= bestAlert //higher alert level || (level.alertEvents[i].level==bestAlert&&level.alertEvents[i].timestamp >= bestTime) )//same alert level, but this one is newer {//NOTE: equal is better because it's later in the array bestEvent = i; bestAlert = level.alertEvents[i].level; bestTime = level.alertEvents[i].timestamp; } } return bestEvent; }
void Rancor_Bite( void ) { int radiusEntNums[128]; int numEnts; const float radius = 100; const float radiusSquared = (radius*radius); int i; vec3_t boltOrg; numEnts = NPC_GetEntsNearBolt( radiusEntNums, radius, NPC->client->renderInfo.crotchBolt, boltOrg );//was gutBolt? for ( i = 0; i < numEnts; i++ ) { gentity_t *radiusEnt = &g_entities[radiusEntNums[i]]; if ( !radiusEnt->inuse ) { continue; } if ( radiusEnt == NPC ) {//Skip the rancor ent continue; } if ( radiusEnt->client == NULL ) {//must be a client continue; } if ( (radiusEnt->client->ps.eFlags2&EF2_HELD_BY_MONSTER) ) {//can't be one already being held continue; } if ( DistanceSquared( radiusEnt->r.currentOrigin, boltOrg ) <= radiusSquared ) { G_Damage( radiusEnt, NPC, NPC, vec3_origin, radiusEnt->r.currentOrigin, Q_irand( 15, 30 ), DAMAGE_NO_ARMOR|DAMAGE_NO_KNOCKBACK, MOD_MELEE ); if ( radiusEnt->health <= 0 && radiusEnt->client ) {//killed them, chance of dismembering if ( !Q_irand( 0, 1 ) ) {//bite something off int hitLoc = Q_irand( G2_MODELPART_HEAD, G2_MODELPART_RLEG ); if ( hitLoc == G2_MODELPART_HEAD ) { NPC_SetAnim( radiusEnt, SETANIM_BOTH, BOTH_DEATH17, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD ); } else if ( hitLoc == G2_MODELPART_WAIST ) { NPC_SetAnim( radiusEnt, SETANIM_BOTH, BOTH_DEATHBACKWARD2, SETANIM_FLAG_OVERRIDE | SETANIM_FLAG_HOLD ); } //radiusEnt->client->dismembered = qfalse; //FIXME: the limb should just disappear, cuz I ate it G_Dismember( radiusEnt, NPC, radiusEnt->r.currentOrigin, hitLoc, 90, 0, radiusEnt->client->ps.torsoAnim, qtrue); //G_DoDismemberment( radiusEnt, radiusEnt->r.currentOrigin, MOD_SABER, 1000, hitLoc, qtrue ); } } G_Sound( radiusEnt, CHAN_AUTO, G_SoundIndex( "sound/chars/rancor/chomp.wav" ) ); } } }
/* ** SetFarClip */ static void SetFarClip( void ) { float farthestCornerDistance = 0; int i; // if not rendering the world (icons, menus, etc) // set a 2k far clip plane if ( tr.refdef.rdflags & RDF_NOWORLDMODEL ) { tr.viewParms.zFar = 2048; return; } // // set far clipping planes dynamically // for ( i = 0; i < 8; i++ ) { vec3_t v; float distance; if ( i & 1 ) { v[0] = tr.viewParms.visBounds[0][0]; } else { v[0] = tr.viewParms.visBounds[1][0]; } if ( i & 2 ) { v[1] = tr.viewParms.visBounds[0][1]; } else { v[1] = tr.viewParms.visBounds[1][1]; } if ( i & 4 ) { v[2] = tr.viewParms.visBounds[0][2]; } else { v[2] = tr.viewParms.visBounds[1][2]; } distance = DistanceSquared(tr.viewParms.or.origin, v); if ( distance > farthestCornerDistance ) { farthestCornerDistance = distance; } } // Bring in the zFar to the distanceCull distance // The sky renders at zFar so need to move it out a little // ...and make sure there is a minimum zfar to prevent problems tr.viewParms.zFar = Com_Clamp(2048.0f, tr.distanceCull * (1.732), sqrtf( farthestCornerDistance )); }
Spectrum PointLight::Sample_L(const pbrt::Point &p, float pEpsilon, const LightSample &ls, float time, Vector *wi, float *pdf, VisibilityTester *visibility) const { *wi = Normalize(lightPos - p); *pdf = 1.f; visibility->SetSegment(p, pEpsilon, lightPos, 0., time); return Intensity / DistanceSquared(lightPos, p); }
LightInfo ProjectionLight::Sample_L(const Point &p, float pEpsilon, const LightSample &ls, float time) const { auto wi = Normalize(lightPos - p); VisibilityTester visibility; visibility.SetSegment(p, pEpsilon, lightPos, 0., time); auto L = Intensity * Projection(-wi) / DistanceSquared(lightPos, p); return LightInfo{L,wi,1.f,visibility}; }
/* ================ G_SelectSpawnBuildable find the nearest buildable of the right type that is spawned/healthy/unblocked etc. ================ */ static gentity_t *G_SelectSpawnBuildable( vec3_t preference, buildable_t buildable ) { gentity_t *search = nullptr; gentity_t *spot = nullptr; while ( ( search = G_IterateEntitiesOfClass( search, BG_Buildable( buildable )->entityName ) ) != nullptr ) { if ( !search->spawned ) { continue; } if ( G_Dead( search ) ) { continue; } if ( search->s.groundEntityNum == ENTITYNUM_NONE ) { continue; } if ( search->clientSpawnTime > 0 ) { continue; } Entity* blocker = nullptr; Vec3 spawnPoint; search->entity->CheckSpawnPoint(blocker, spawnPoint); if (blocker) { continue; } if ( !spot || DistanceSquared( preference, search->s.origin ) < DistanceSquared( preference, spot->s.origin ) ) { spot = search; } } return spot; }
Spectrum GonioPhotometricLight::Sample_L(const Point &P, float u1, float u2, Vector *wo, float *pdf, VisibilityTester *visibility) const { *wo = Normalize(lightPos - P); *pdf = 1.f; visibility->SetSegment(P, lightPos); return Intensity * Scale(-*wo) / DistanceSquared(lightPos, P); }
Spectrum SpotLight::Sample_Li(const Interaction &ref, const Point2f &u, Vector3f *wi, Float *pdf, VisibilityTester *vis) const { *wi = Normalize(pLight - ref.p); *pdf = 1.f; *vis = VisibilityTester(ref, Interaction(pLight, ref.time, medium)); return intensity * Falloff(-*wi) / DistanceSquared(pLight, ref.p); }
void Bot::CheckAlertSpots(const StaticVector<edict_t *, MAX_CLIENTS> &visibleTargets) { float scores[MAX_ALERT_SPOTS]; // First compute scores (good for instruction cache) for (unsigned i = 0; i < alertSpots.size(); ++i) { float score = 0.0f; const auto &alertSpot = alertSpots[i]; const float squareRadius = alertSpot.radius * alertSpot.radius; const float invRadius = 1.0f / alertSpot.radius; for (const edict_t *ent: visibleTargets) { float squareDistance = DistanceSquared(ent->s.origin, alertSpot.origin.Data()); if (squareDistance > squareRadius) continue; float distance = Q_RSqrt(squareDistance + 0.001f); score += 1.0f - distance * invRadius; // Put likely case first if (!(ent->s.effects & EF_CARRIER)) score *= alertSpot.regularEnemyInfluenceScale; else score *= alertSpot.carrierEnemyInfluenceScale; } // Clamp score by a max value clamp_high(score, 3.0f); // Convert score to [0, 1] range score /= 3.0f; // Get a square root of score (values closer to 0 gets scaled more than ones closer to 1) score = 1.0f / Q_RSqrt(score + 0.001f); // Sanitize clamp(score, 0.0f, 1.0f); scores[i] = score; } // Then call callbacks const unsigned levelTime = level.time; for (unsigned i = 0; i < alertSpots.size(); ++i) { auto &alertSpot = alertSpots[i]; unsigned nonReportedFor = levelTime - alertSpot.lastReportedAt; if (nonReportedFor >= 1000) alertSpot.lastReportedScore = 0.0f; // Since scores are sanitized, they are in range [0.0f, 1.0f], and abs(scoreDelta) is in range [-1.0f, 1.0f]; float scoreDelta = scores[i] - alertSpot.lastReportedScore; if (scoreDelta >= 0) { if (nonReportedFor >= 1000 - scoreDelta * 500) alertSpot.Alert(this, scores[i]); } else { if (nonReportedFor >= 500 - scoreDelta * 500) alertSpot.Alert(this, scores[i]); } } }
Interaction Sphere::Sample(const Interaction &ref, const Point2f &u) const { // Compute coordinate system for sphere sampling Point3f pCenter = (*ObjectToWorld)(Point3f(0, 0, 0)); Vector3f wc = Normalize(pCenter - ref.p); Vector3f wcX, wcY; CoordinateSystem(wc, &wcX, &wcY); // Sample uniformly on sphere if $\pt{}$ is inside it Point3f pOrigin = OffsetRayOrigin(ref.p, ref.pError, ref.n, pCenter - ref.p); if (DistanceSquared(pOrigin, pCenter) <= radius * radius) return Sample(u); // Sample sphere uniformly inside subtended cone // Compute $\theta$ and $\phi$ values for sample in cone Float sinThetaMax2 = radius * radius / DistanceSquared(ref.p, pCenter); Float cosThetaMax = std::sqrt(std::max((Float)0, 1 - sinThetaMax2)); Float cosTheta = (1 - u[0]) + u[0] * cosThetaMax; Float sinTheta = std::sqrt(1 - cosTheta * cosTheta); Float phi = u[1] * 2 * Pi; // Compute angle $\alpha$ from center of sphere to sampled point on surface Float dc = Distance(ref.p, pCenter); Float ds = dc * cosTheta - std::sqrt(std::max( (Float)0, radius * radius - dc * dc * sinTheta * sinTheta)); Float cosAlpha = (dc * dc + radius * radius - ds * ds) / (2 * dc * radius); Float sinAlpha = std::sqrt(std::max((Float)0, 1 - cosAlpha * cosAlpha)); // Compute surface normal and sampled point on sphere Vector3f nObj = SphericalDirection(sinAlpha, cosAlpha, phi, -wcX, -wcY, -wc); Point3f pObj = radius * Point3f(nObj.x, nObj.y, nObj.z); // Return _Interaction_ for sampled point on sphere Interaction it; // Reproject _pObj_ to sphere surface and compute _pObjError_ pObj *= radius / Distance(pObj, Point3f(0, 0, 0)); Vector3f pObjError = gamma(5) * Abs((Vector3f)pObj); it.p = (*ObjectToWorld)(pObj, pObjError, &it.pError); it.n = (*ObjectToWorld)(Normal3f(nObj)); if (reverseOrientation) it.n *= -1.f; return it; }
static float AStarHeuristic(void *fromNode, void *toNode, void *context) { // Simple Euclidean Vec2i *v1 = fromNode; Vec2i *v2 = toNode; UNUSED(context); return (float)sqrt(DistanceSquared( Vec2iCenterOfTile(*v1), Vec2iCenterOfTile(*v2))); }
// GonioPhotometricLight Method Definitions Spectrum GonioPhotometricLight::Sample_L(const Interaction &ref, const Point2f &sample, Vector3f *wi, Float *pdf, VisibilityTester *vis) const { *wi = Normalize(pLight - ref.p); *pdf = 1.f; *vis = VisibilityTester(ref, Interaction(pLight, ref.time, medium)); return intensity * Scale(-*wi) / DistanceSquared(pLight, ref.p); }
/* ================ G_SelectSpawnBuildable find the nearest buildable of the right type that is spawned/healthy/unblocked etc. ================ */ static gentity_t *G_SelectSpawnBuildable( vec3_t preference, buildable_t buildable ) { gentity_t *search, *spot; search = spot = NULL; while ( ( search = G_Find( search, FOFS( classname ), BG_Buildable( buildable )->entityName ) ) != NULL ) { if ( !search->spawned ) { continue; } if ( search->health <= 0 ) { continue; } if ( search->s.groundEntityNum == ENTITYNUM_NONE ) { continue; } if ( search->clientSpawnTime > 0 ) { continue; } if ( G_CheckSpawnPoint( search->s.number, search->s.origin, search->s.origin2, buildable, NULL ) != NULL ) { continue; } if ( !spot || DistanceSquared( preference, search->s.origin ) < DistanceSquared( preference, spot->s.origin ) ) { spot = search; } } return spot; }
// not 100% sure how this one should work and PVP affects ... void Aura::ProcessOnAllFriendlies(Mob *owner) { auto &mob_list = entity_list.GetMobList(); // read only reference so we can do it all inline std::set<int> delayed_remove; bool is_buff = IsBuffSpell(spell_id); // non-buff spells don't cast on enter for (auto &e : mob_list) { auto mob = e.second; if (mob->IsClient() || mob->IsPetOwnerClient() || mob->IsMerc()) { auto it = casted_on.find(mob->GetID()); if (it != casted_on.end()) { // we are already on the list, let's check for removal if (DistanceSquared(GetPosition(), mob->GetPosition()) > distance) delayed_remove.insert(mob->GetID()); } else { // not on list, lets check if we're in range if (DistanceSquared(GetPosition(), mob->GetPosition()) <= distance) { casted_on.insert(mob->GetID()); if (is_buff) SpellFinished(spell_id, mob); } } } } for (auto &e : delayed_remove) { auto mob = entity_list.GetMob(e); if (mob != nullptr && is_buff) // some auras cast instant spells so no need to remove mob->BuffFadeBySpellIDAndCaster(spell_id, GetID()); casted_on.erase(e); } // so if we have a cast timer and our set isn't empty and timer is disabled we need to enable it if (cast_timer.GetDuration() > 0 && !cast_timer.Enabled() && !casted_on.empty()) cast_timer.Start(); if (!cast_timer.Enabled() || !cast_timer.Check()) return; for (auto &e : casted_on) { auto mob = entity_list.GetMob(e); if (mob != nullptr) SpellFinished(spell_id, mob); } }
Spectrum ProjectionLight::Sample_Li(const Interaction &ref, const Point2f &u, Vector3f *wi, Float *pdf, VisibilityTester *vis) const { ProfilePhase _(Prof::LightSample); *wi = Normalize(pLight - ref.p); *pdf = 1; *vis = VisibilityTester(ref, Interaction(pLight, ref.time, mediumInterface)); return I * Projection(-*wi) / DistanceSquared(pLight, ref.p); }
/* ------------------------- NPC_CheckSoundEvents ------------------------- */ static int G_CheckSoundEvents( gentity_t *self, float maxHearDist, int ignoreAlert, qboolean mustHaveOwner, int minAlertLevel ) { int bestEvent = -1; int bestAlert = -1; int bestTime = -1; int i; float dist, radius; maxHearDist *= maxHearDist; for ( i = 0; i < level.numAlertEvents; i++ ) { //are we purposely ignoring this alert? if ( i == ignoreAlert ) continue; //We're only concerned about sounds if ( level.alertEvents[i].type != AET_SOUND ) continue; //must be at least this noticable if ( level.alertEvents[i].level < minAlertLevel ) continue; //must have an owner? if ( mustHaveOwner && !level.alertEvents[i].owner ) continue; //Must be within range dist = DistanceSquared( level.alertEvents[i].position, self->r.currentOrigin ); //can't hear it if ( dist > maxHearDist ) continue; radius = level.alertEvents[i].radius * level.alertEvents[i].radius; if ( dist > radius ) continue; if ( level.alertEvents[i].addLight ) {//a quiet sound, must have LOS to hear it if ( G_ClearLOS5( self, level.alertEvents[i].position ) == qfalse ) {//no LOS, didn't hear it continue; } } //See if this one takes precedence over the previous one if ( level.alertEvents[i].level >= bestAlert //higher alert level || (level.alertEvents[i].level==bestAlert&&level.alertEvents[i].timestamp >= bestTime) )//same alert level, but this one is newer {//NOTE: equal is better because it's later in the array bestEvent = i; bestAlert = level.alertEvents[i].level; bestTime = level.alertEvents[i].timestamp; } } return bestEvent; }
// Return the closest pathgrid point index from the specified position // coordinates. NOTE: Does not check if there is a sensible way to get there // (e.g. a cliff in front). // // NOTE: pos is expected to be in local coordinates, as is grid->mPoints // static int GetClosestPoint(const ESM::Pathgrid* grid, const osg::Vec3f& pos) { assert(grid && !grid->mPoints.empty()); float distanceBetween = DistanceSquared(grid->mPoints[0], pos); int closestIndex = 0; // TODO: if this full scan causes performance problems mapping pathgrid // points to a quadtree may help for(unsigned int counter = 1; counter < grid->mPoints.size(); counter++) { float potentialDistBetween = DistanceSquared(grid->mPoints[counter], pos); if(potentialDistBetween < distanceBetween) { distanceBetween = potentialDistBetween; closestIndex = counter; } } return closestIndex; }
/* ============== IsHeadShotWeapon ============== */ qboolean IsHeadShotWeapon( int mod, gentity_t *targ, gentity_t *attacker ) { // distance rejection if ( DistanceSquared( targ->r.currentOrigin, attacker->r.currentOrigin ) > ( g_headshotMaxDist.integer * g_headshotMaxDist.integer ) ) { return qfalse; } if ( attacker->aiCharacter ) { // ai's are always allowed headshots from these weapons if ( mod == MOD_SNIPERRIFLE || mod == MOD_SNOOPERSCOPE ) { return qtrue; } if ( g_gameskill.integer != GSKILL_MAX ) { // ai's allowed headshots in skill==GSKILL_MAX return qfalse; } } switch ( targ->aiCharacter ) { // get out quick for ai's that don't take headshots case AICHAR_ZOMBIE: case AICHAR_WARZOMBIE: case AICHAR_HELGA: // boss1 (beast) case AICHAR_LOPER: case AICHAR_VENOM: //----(SA) added return qfalse; default: break; } switch ( mod ) { // players are allowed headshots from these weapons case MOD_LUGER: case MOD_COLT: case MOD_AKIMBO: case MOD_MP40: case MOD_THOMPSON: case MOD_STEN: case MOD_BAR: case MOD_FG42: case MOD_MAUSER: case MOD_GARAND: case MOD_SILENCER: case MOD_FG42SCOPE: case MOD_SNOOPERSCOPE: case MOD_SNIPERRIFLE: return qtrue; } return qfalse; }
void EntityList::DescribeAggro(Client *towho, NPC *from_who, float d, bool verbose) { float d2 = d*d; towho->Message(0, "Describing aggro for %s", from_who->GetName()); bool engaged = from_who->IsEngaged(); if(engaged) { Mob *top = from_who->GetHateTop(); towho->Message(0, ".. I am currently fighting with %s", top == nullptr?"(nullptr)":top->GetName()); } bool check_npcs = from_who->WillAggroNPCs(); if(verbose) { char namebuf[256]; int my_primary = from_who->GetPrimaryFaction(); Mob *own = from_who->GetOwner(); if(own != nullptr) my_primary = own->GetPrimaryFaction(); if(my_primary == 0) { strcpy(namebuf, "(No faction)"); } else if(my_primary < 0) { strcpy(namebuf, "(Special faction)"); } else { if(!database.GetFactionName(my_primary, namebuf, sizeof(namebuf))) strcpy(namebuf, "(Unknown)"); } towho->Message(0, ".. I am on faction %s (%d)\n", namebuf, my_primary); } for (auto it = mob_list.begin(); it != mob_list.end(); ++it) { Mob *mob = it->second; if (mob->IsClient()) //also ensures that mob != around continue; if (DistanceSquared(mob->GetPosition(), from_who->GetPosition()) > d2) continue; if (engaged) { uint32 amm = from_who->GetHateAmount(mob); if (amm == 0) towho->Message(0, "... %s is not on my hate list.", mob->GetName()); else towho->Message(0, "... %s is on my hate list with value %lu", mob->GetName(), (unsigned long)amm); } else if (!check_npcs && mob->IsNPC()) { towho->Message(0, "... %s is an NPC and my npc_aggro is disabled.", mob->GetName()); } else { from_who->DescribeAggro(towho, mob, verbose); } } }
real64 MaxSquaredDistancePointToRect (const dng_point_real64 &point, const dng_rect_real64 &rect) { real64 distSqr = DistanceSquared (point, rect.TL ()); distSqr = Max_real64 (distSqr, DistanceSquared (point, rect.BL ())); distSqr = Max_real64 (distSqr, DistanceSquared (point, rect.BR ())); distSqr = Max_real64 (distSqr, DistanceSquared (point, rect.TR ())); return distSqr; }
int DistanceToGoalSquared( gentity_t *self ) { vec3_t targetPos; vec3_t selfPos; //safety check for morons who use this incorrectly if ( !( self->botMind ) ) { return -1; } BotGetTargetPos( self->botMind->goal, targetPos ); VectorCopy( self->s.origin, selfPos ); return DistanceSquared( selfPos, targetPos ); }
// solar: causes caster to hit every mob within dist range of center with // a bard pulse of spell_id. // NPC spells will only affect other NPCs with compatible faction void EntityList::AEBardPulse(Mob *caster, Mob *center, uint16 spell_id, bool affect_caster) { Mob *curmob; float dist = caster->GetAOERange(spell_id); float dist2 = dist * dist; bool bad = IsDetrimentalSpell(spell_id); bool isnpc = caster->IsNPC(); for (auto it = mob_list.begin(); it != mob_list.end(); ++it) { curmob = it->second; if (curmob == center) //do not affect center continue; if (curmob == caster && !affect_caster) //watch for caster too continue; if (DistanceSquared(center->GetPosition(), curmob->GetPosition()) > dist2) //make sure they are in range continue; if (isnpc && curmob->IsNPC()) { //check npc->npc casting FACTION_VALUE f = curmob->GetReverseFactionCon(caster); if (bad) { //affect mobs that are on our hate list, or //which have bad faction with us if (!(caster->CheckAggro(curmob) || f == FACTION_THREATENLY || f == FACTION_SCOWLS) ) continue; } else { //only affect mobs we would assist. if (!(f <= FACTION_AMIABLE)) continue; } } //finally, make sure they are within range if (bad) { if (!center->CheckLosFN(curmob)) continue; } else { // check to stop casting beneficial ae buffs (to wit: bard songs) on enemies... // See notes in AESpell() above for more info. if (caster->IsAttackAllowed(curmob, true)) continue; if (caster->CheckAggro(curmob)) continue; AddHealAggro(curmob, caster, caster->CheckHealAggroAmount(spell_id, curmob)); } //if we get here... cast the spell. curmob->BardPulse(spell_id, caster); } if (caster->IsClient()) caster->CastToClient()->CheckSongSkillIncrease(spell_id); }
float Shape::Pdf(const Point &p, const Vector &wi) const { // Intersect sample ray with area light geometry DifferentialGeometry dgLight; Ray ray(p, wi, 1e-3f); ray.depth = -1; // temporary hack to ignore alpha mask float thit, rayEpsilon; if (!Intersect(ray, &thit, &rayEpsilon, &dgLight)) return 0.; // Convert light sample weight to solid angle measure float pdf = DistanceSquared(p, ray(thit)) / (AbsDot(dgLight.nn, -wi) * Area()); if (isinf(pdf)) pdf = 0.f; return pdf; }