示例#1
0
/*
================
G_ProcessMine

If an enemy is close to the entity, go boom!
================
*/
void G_ProcessMine(gentity_t *ent) {
    int i, total_entities, entityList[MAX_GENTITIES];
    vec3_t range, mins, maxs;
    gentity_t *target;

    // Set the next time to run this check (can be overwritten below)
    ent->nextthink = level.time + MINE_CHECK_FREQUENCY;

    // Grab all entities around us
    VectorSet(range, MINE_DETECT, MINE_DETECT, MINE_DETECT);
    VectorAdd(ent->s.origin, range, maxs);
    VectorSubtract(ent->s.origin, range, mins);

    total_entities = trap_EntitiesInBox(mins, maxs, entityList, MAX_GENTITIES);

    // Loop entities looking for an enemy body
    for(i=0; i<total_entities; i++) {
        target = &g_entities[entityList[i]];
        if(target->client && target->client->ps.stats[ STAT_TEAM ] == TEAM_ALIENS) {
            if (G_Visible( ent, target, MASK_SHOT ))
            {
                // Found an enemy, boom time!
                ent->nextthink = level.time + MINE_BOOM_TIME;
                ent->think = G_ExplodeMissile;
                return;
            }
        }
    }
}
示例#2
0
/*
================
G_ProcessFlare

If an player is close to the entity, hurt!
================
*/
void G_ProcessFlare(gentity_t *ent) {
    int i, total_entities, entityList[MAX_GENTITIES];
    vec3_t range, mins, maxs;
    gentity_t *target;

    if (level.time > ent->s.time + 30000)
    {
        ent->nextthink = level.time + 100;
        ent->think = G_ExplodeMissile;
        return;
    }

    // Set the next time to run this check (can be overwritten below)
    ent->nextthink = level.time + FLARE_CHECK_FREQUENCY;

    // Grab all entities around us
    VectorSet(range, FLARE_DETECT, FLARE_DETECT, FLARE_DETECT);
    VectorAdd(ent->s.origin, range, maxs);
    VectorSubtract(ent->s.origin, range, mins);

    total_entities = trap_EntitiesInBox(mins, maxs, entityList, MAX_GENTITIES);

    // Loop entities looking for an enemy body
    for(i=0; i<total_entities; i++) {
        target = &g_entities[entityList[i]];
        if(target->client) {
            if (G_Visible( ent, target, MASK_SHOT ))
            {
                // Found an enemy, hurt time!
                G_Damage( target, ent, ent->parent, NULL, ent->s.origin, ent->damage, 0, ent->methodOfDeath );

                //ent->nextthink = level.time + MINE_BOOM_TIME;
                //ent->think = G_ExplodeMissile;
                return;
            }
        }
    }
}
示例#3
0
//==========================================
// BOT_DMclass_FindEnemy
// Scan for enemy (simplifed for now to just pick any visible enemy)
//==========================================
void BOT_DMclass_FindEnemy( edict_t *self )
{
#define WEIGHT_MAXDISTANCE_FACTOR 15000
	nav_ents_t *goalEnt;
	edict_t *bestTarget = NULL;
	float dist, weight, bestWeight = 9999999;
	vec3_t forward, vec;
	int i;

	if( G_ISGHOSTING( self ) 
		|| GS_MatchState() == MATCH_STATE_COUNTDOWN
		|| GS_ShootingDisabled() )
	{
		self->ai->enemyReactionDelay = 0;
		self->enemy = self->ai->latched_enemy = NULL;
		return;
	}

	// we also latch NULL enemies, so the bot can loose them
	if( self->ai->enemyReactionDelay > 0 )
	{
		self->ai->enemyReactionDelay -= game.frametime;
		return;
	}

	self->enemy = self->ai->latched_enemy;

	FOREACH_GOALENT( goalEnt )
	{
		i = goalEnt->id;

		if( !goalEnt->ent || !goalEnt->ent->r.inuse )
			continue;

		if( !goalEnt->ent->r.client ) // this may be changed, there could be enemies which aren't clients
			continue;

		if( G_ISGHOSTING( goalEnt->ent ) )
			continue;

		if( self->ai->status.entityWeights[i] <= 0 || goalEnt->ent->flags & (FL_NOTARGET|FL_BUSY) )
			continue;

		if( GS_TeamBasedGametype() && goalEnt->ent->s.team == self->s.team )
			continue;

		dist = DistanceFast( self->s.origin, goalEnt->ent->s.origin );

		// ignore very soft weighted enemies unless they are in your face
		if( dist > 500 && self->ai->status.entityWeights[i] <= 0.1f )
			continue;

		//if( dist > 700 && dist > WEIGHT_MAXDISTANCE_FACTOR * self->ai->status.entityWeights[i] )
		//	continue;

		weight = dist / self->ai->status.entityWeights[i];

		if( weight < bestWeight )
		{
			if( trap_inPVS( self->s.origin, goalEnt->ent->s.origin ) && G_Visible( self, goalEnt->ent ) )
			{
				bool close = dist < 2000 || goalEnt->ent == self->ai->last_attacker;

				if( !close )
				{
					VectorSubtract( goalEnt->ent->s.origin, self->s.origin, vec );
					VectorNormalize( vec );
					close = DotProduct( vec, forward ) > 0.3;
				}

				if( close )				
				{
					bestWeight = weight;
					bestTarget = goalEnt->ent;
				}
			}
		}
	}

	AI_NewEnemyInView( self, bestTarget );
#undef WEIGHT_MAXDISTANCE_FACTOR
}
void explodedretch(gentity_t *ent)
{
    int       i;
    int         entityList[ MAX_GENTITIES ];
		vec3_t      range;
		vec3_t      mins, maxs;
		int         num;
		gentity_t   *enemy;
		float       creepSize = (float)650;
		int freezedcounter = 0;
    
    //gentity_t *gren;
    if(ent->client->ps.persistant[ PERS_CREDIT ] < 1) //Neeeddd fix <3
    {
        trap_SendServerCommand( ent-g_entities, "print \"^5Overmind: ^7You need 1 evos to explode.\n\"" );
    }
    else
    {
        ent->client->ps.persistant[ PERS_CREDIT ] -= 1;
        G_AddPredictableEvent( ent, EV_ALIEN_EVOLVE, 0 );
        G_RadiusDamage( ent->r.currentOrigin, ent, 200,
                     200, ent, MOD_GRENADE);
        G_Damage( ent, ent, ent, NULL, NULL, 10000, 0, MOD_UNKNOWN );
        
        
        //Slow down enemy around.
        VectorSet( range, creepSize, creepSize, creepSize );

        VectorAdd( ent->s.origin, range, maxs );
        VectorSubtract( ent->s.origin, range, mins );

        //find enemys around me
        num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
        for( i = 0; i < num; i++ )
        {
            enemy = &g_entities[ entityList[ i ] ];

            if( enemy->flags & FL_NOTARGET )
                continue;
            if( enemy->client && (enemy->client->ps.stats[ STAT_PTEAM ] != ent->client->ps.stats[ STAT_PTEAM ] ) && G_Visible( ent, enemy ) )
            {
                //enemy->client->ps.stats[ STAT_STATE ] |= SS_CREEPSLOWED;
                enemy->client->ps.stats[ STAT_STATE ] |= SS_ICEWAVED;
                enemy->client->lastCreepSlowTime = level.time + 5000;
                freezedcounter++;
                //G_SelectiveRadiusDamage( ent->s.pos.trBase, ent, (float)dmg, (float)500, ent, MOD_SLOWBLOB, ent->client->ps.stats[ STAT_PTEAM ] );
            }
        }
        if(ent->client){
        //29  	Freezing Field  	Icewave over 5 enemies in 1 icewave 
			if(ent->client->pers.badges[ 29 ] != 1  && freezedcounter >= 5)
			{
				ent->client->pers.badgeupdate[29] = 1;
				ent->client->pers.badges[29] = 1;
				G_WinBadge( ent, 29 );
			}
		}
    }
    /*
    
    if(ent->client->pers.teamSelection != PTE_HUMANS
    && ent->client->pers.teamSelection != PTE_ALIENS )
    {  
        trap_SendServerCommand( ent-g_entities, va(
        "print \"^1You must be on a team\n\"" ) );
                return qfalse;
    }

    if(ent->client->pers.classSelection == PCL_NONE)
    {  
        trap_SendServerCommand( ent-g_entities, va(
        "print \"^1You must be alive\n\"" ) );
                return qfalse;
    }
    if(ent->client->pers.energy >= 500)
    {  
        if(ent->client->pers.teamSelection == PTE_HUMANS)
        {
            dmg = 3;
        }
        if(ent->client->pers.teamSelection == PTE_ALIENS)
        {
            dmg = 1;
        }

        ent->client->pers.energy-= 500;
        G_AddEvent( ent, EV_ALIEN_BUILDABLE_EXPLOSION, 0 );

        VectorSet( range, creepSize, creepSize, creepSize );

        VectorAdd( ent->s.origin, range, maxs );
        VectorSubtract( ent->s.origin, range, mins );

        //find enemys around me
        num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES );
        for( i = 0; i < num; i++ )
        {
            enemy = &g_entities[ entityList[ i ] ];

            if( enemy->flags & FL_NOTARGET )
                continue;
            if( enemy->client && (enemy->client->ps.stats[ STAT_PTEAM ] != ent->client->ps.stats[ STAT_PTEAM ] ) && G_Visible( ent, enemy ) )
            {
                //enemy->client->ps.stats[ STAT_STATE ] |= SS_CREEPSLOWED;
                enemy->client->ps.stats[ STAT_STATE ] |= SS_ICEWAVED;
                enemy->client->lastCreepSlowTime = level.time + 5000;
                //G_SelectiveRadiusDamage( ent->s.pos.trBase, ent, (float)dmg, (float)500, ent, MOD_SLOWBLOB, ent->client->ps.stats[ STAT_PTEAM ] );
            }
        }
        return qtrue;
    }*/
}
示例#5
0
文件: bot.cpp 项目: DenMSC/qfusion
void Bot::RegisterVisibleEnemies()
{
    if(G_ISGHOSTING(self) || GS_MatchState() == MATCH_STATE_COUNTDOWN || GS_ShootingDisabled())
        return;

    CheckIsInThinkFrame(__FUNCTION__);

    // Compute look dir before loop
    vec3_t lookDir;
    AngleVectors(self->s.angles, lookDir, nullptr, nullptr);

    float fov = 110.0f + 69.0f * Skill();
    float dotFactor = cosf((float)DEG2RAD(fov / 2));

    struct EntAndDistance
    {
        int entNum;
        float distance;

        EntAndDistance(int entNum_, float distance_): entNum(entNum_), distance(distance_) {}
        bool operator<(const EntAndDistance &that) const { return distance < that.distance; }
    };

    // Do not call inPVS() and G_Visible() for potential targets inside a loop for all clients.
    // In worst case when all bots may see each other we get N^2 traces and PVS tests
    // First, select all candidate targets along with distance to a bot.
    // Then choose not more than BotBrain::maxTrackedEnemies nearest enemies for calling OnEnemyViewed()
    // It may cause data loss (far enemies may have higher logical priority),
    // but in a common good case (when there are few visible enemies) it preserves data,
    // and in the worst case mentioned above it does not act weird from player POV and prevents server hang up.
    // Note: non-client entities also may be candidate targets.
    StaticVector<EntAndDistance, MAX_EDICTS> candidateTargets;

    for (int i = 1; i < game.numentities; ++i)
    {
        edict_t *ent = game.edicts + i;
        if (botBrain.MayNotBeFeasibleEnemy(ent))
            continue;

        // Reject targets quickly by fov
        Vec3 toTarget(ent->s.origin);
        toTarget -= self->s.origin;
        float squareDistance = toTarget.SquaredLength();
        if (squareDistance < 1)
            continue;
        float invDistance = Q_RSqrt(squareDistance);
        toTarget *= invDistance;
        if (toTarget.Dot(lookDir) < dotFactor)
            continue;

        // It seams to be more instruction cache-friendly to just add an entity to a plain array
        // and sort it once after the loop instead of pushing an entity in a heap on each iteration
        candidateTargets.emplace_back(EntAndDistance(ENTNUM(ent), 1.0f / invDistance));
    }

    std::sort(candidateTargets.begin(), candidateTargets.end());

    // Select inPVS/visible targets first to aid instruction cache, do not call callbacks in loop
    StaticVector<edict_t *, MAX_CLIENTS> targetsInPVS;
    StaticVector<edict_t *, MAX_CLIENTS> visibleTargets;

    static_assert(AiBaseEnemyPool::MAX_TRACKED_ENEMIES <= MAX_CLIENTS, "targetsInPVS capacity may be exceeded");

    for (int i = 0, end = std::min(candidateTargets.size(), botBrain.MaxTrackedEnemies()); i < end; ++i)
    {
        edict_t *ent = game.edicts + candidateTargets[i].entNum;
        if (trap_inPVS(self->s.origin, ent->s.origin))
            targetsInPVS.push_back(ent);
    }

    for (auto ent: targetsInPVS)
        if (G_Visible(self, ent))
            visibleTargets.push_back(ent);

    // Call bot brain callbacks on visible targets
    for (auto ent: visibleTargets)
        botBrain.OnEnemyViewed(ent);

    botBrain.AfterAllEnemiesViewed();

    CheckAlertSpots(visibleTargets);
}
示例#6
0
//==========================================
// BOT_DMclass_FindEnemy
// Scan for enemy (simplifed for now to just pick any visible enemy)
//==========================================
void BOT_DMclass_FindEnemy( edict_t *self )
{
#define WEIGHT_MAXDISTANCE_FACTOR 15000
	nav_ents_t *goalEnt;
	edict_t *bestTarget = NULL;
	float dist, weight, bestWeight = 9999999;
	int i;

	if( G_ISGHOSTING( self ) 
		|| GS_MatchState() == MATCH_STATE_COUNTDOWN
		|| GS_ShootingDisabled() )
	{
		self->ai.enemyReactionDelay = 0;
		self->enemy = self->ai.latched_enemy = NULL;
		return;
	}

	// we also latch NULL enemies, so the bot can loose them
	if( self->ai.enemyReactionDelay > 0 )
	{
		self->ai.enemyReactionDelay -= game.frametime;
		return;
	}

	self->enemy = self->ai.latched_enemy;

	for( i = 0; i < nav.num_goalEnts; i++ )
	{
		goalEnt = &nav.goalEnts[i];

		if( !goalEnt->ent || !goalEnt->ent->r.inuse )
			continue;

		if( !goalEnt->ent->r.client ) // this may be changed, there could be enemies which aren't clients
			continue;

		if( G_ISGHOSTING( goalEnt->ent ) )
			continue;

		if( self->ai.status.entityWeights[i] <= 0 || goalEnt->ent->ai.notarget )
			continue;

		if( GS_TeamBasedGametype() && goalEnt->ent->s.team == self->s.team )
			continue;

		dist = DistanceFast( self->s.origin, goalEnt->ent->s.origin );

		// ignore very soft weighted enemies unless they are in your face
		if( dist > 500 && self->ai.status.entityWeights[i] <= 0.1f )
			continue;

		if( dist > 700 && dist > WEIGHT_MAXDISTANCE_FACTOR * self->ai.status.entityWeights[i] )
			continue;

		if( trap_inPVS( self->s.origin, goalEnt->ent->s.origin ) && G_Visible( self, goalEnt->ent ) )
		{
			weight = dist / self->ai.status.entityWeights[i];

			if( ( dist < 350 ) || G_InFront( self, goalEnt->ent ) )
			{
				if( weight < bestWeight )
				{
					bestWeight = weight;
					bestTarget = goalEnt->ent;
				}
			}
		}
	}

	AI_NewEnemyInView( self, bestTarget );
#undef WEIGHT_MAXDISTANCE_FACTOR
}
示例#7
0
/*
=============
ai_checkattack

Decides if we're going to attack or do something else
used by ai_run and ai_stand
=============
*/
bool ai_checkattack (edict_t *self, float dist)
{
	vec3_t		temp;
	bool	hesDeadJim;

// this causes monsters to run blindly to the combat point w/o firing
	if (self->goalentity)
	{
		if (self->monsterinfo.aiflags & AI_COMBAT_POINT)
			return false;

		if (self->monsterinfo.aiflags & AI_SOUND_TARGET)
		{
			if (level.time - self->enemy->teleport_time > 5000)
			{
				if (self->goalentity == self->enemy) {
					if (self->movetarget)
						self->goalentity = self->movetarget;
					else
						self->goalentity = NULL;
				}
				self->monsterinfo.aiflags &= ~AI_SOUND_TARGET;
				if (self->monsterinfo.aiflags & AI_TEMP_STAND_GROUND)
					self->monsterinfo.aiflags &= ~(AI_STAND_GROUND | AI_TEMP_STAND_GROUND);
			}
			else
			{
				self->show_hostile = level.time + 1000;
				return false;
			}
		}
	}

	enemy_vis = false;

// see if the enemy is dead
	hesDeadJim = false;
	if ((!self->enemy) || (!self->enemy->r.inuse))
	{
		hesDeadJim = true;
	}
	else if (self->monsterinfo.aiflags & AI_MEDIC)
	{
		if (self->enemy->health > 0)
		{
			hesDeadJim = true;
			self->monsterinfo.aiflags &= ~AI_MEDIC;
		}
	}
	else
	{
		if (self->monsterinfo.aiflags & AI_BRUTAL)
		{
			if (self->enemy->health <= -80)
				hesDeadJim = true;
		}
		else
		{
			if (self->enemy->health <= 0)
				hesDeadJim = true;
		}
	}

	if (hesDeadJim)
	{
		self->enemy = NULL;
	// FIXME: look all around for other targets
		if (self->oldenemy && self->oldenemy->health > 0)
		{
			self->enemy = self->oldenemy;
			self->oldenemy = NULL;
			HuntTarget (self);
		}
		else
		{
			if (self->movetarget)
			{
				self->goalentity = self->movetarget;
				self->monsterinfo.walk (self);
			}
			else
			{
				// we need the pausetime otherwise the stand code
				// will just revert to walking with no target and
				// the monsters will wonder around aimlessly trying
				// to hunt the world entity
				self->monsterinfo.pausetime = level.time + 100000000;
				self->monsterinfo.stand (self);
			}
			return true;
		}
	}

	self->show_hostile = level.time + 1000;		// wake up other monsters

// check knowledge of enemy
	enemy_vis = G_Visible(self, self->enemy);
	if (enemy_vis)
	{
		self->monsterinfo.search_time = level.time + 5000;
		VectorCopy (self->enemy->s.origin, self->monsterinfo.last_sighting);
	}

// look for other coop players here
//	if (coop && self->monsterinfo.search_time < level.time)
//	{
//		if (FindTarget (self))
//			return true;
//	}

	enemy_infront = G_InFront(self, self->enemy);
	enemy_range = range(self, self->enemy);
	VectorSubtract (self->enemy->s.origin, self->s.origin, temp);
	enemy_yaw = vectoyaw(temp);


	// JDC self->ideal_yaw = enemy_yaw;

	if (self->monsterinfo.attack_state == AS_MISSILE)
	{
		ai_run_missile (self);
		return true;
	}
	if (self->monsterinfo.attack_state == AS_MELEE)
	{
		ai_run_melee (self);
		return true;
	}

	// if enemy is not currently visible, we will never attack
	if (!enemy_vis)
		return false;

	return self->monsterinfo.checkattack (self);
}
示例#8
0
/*
===========
FindTarget

Self is currently not attacking anything, so try to find a target

Returns TRUE if an enemy was sighted

When a player fires a missile, the point of impact becomes a fakeplayer so
that monsters that see the impact will respond as if they had seen the
player.

To avoid spending too much time, only a single client (or fakeclient) is
checked each frame.  This means multi player games will have slightly
slower noticing monsters.
============
*/
bool FindTarget (edict_t *self)
{
	edict_t		*client;
	bool	heardit;
	bool    noise;
	int			r;

	if (self->monsterinfo.aiflags & AI_GOOD_GUY)
	{
		if (self->goalentity && self->goalentity->r.inuse && self->goalentity->classname)
		{
			if (strcmp(self->goalentity->classname, "target_actor") == 0)
				return false;
		}

		//FIXME look for monsters?
		return false;
	}

	// if we're going to a combat point, just proceed
	if (self->monsterinfo.aiflags & AI_COMBAT_POINT)
		return false;

// if the first spawnflag bit is set, the monster will only wake up on
// really seeing the player, not another monster getting angry or hearing
// something

// revised behavior so they will wake up if they "see" a player make a noise
// but not weapon impact/explosion noises

	heardit = false;
	if ((level.sight_entity_framenum+1 >= level.framenum) && !(self->spawnflags & 1) )
	{
		client = level.sight_entity;
		if (client->enemy == self->enemy)
		{
			return false;
		}
	}
	else if (level.sound_entity_framenum+1 >= level.framenum)
	{
		client = level.sound_entity;
		heardit = true;
	}
	else if (!(self->enemy) && (level.sound2_entity_framenum+1 >= level.framenum) && !(self->spawnflags & 1) )
	{
		client = level.sound2_entity;
		heardit = true;
	}
	else
	{
		client = level.sight_client;
		if (!client)
			return false;	// no clients to get mad at
	}

	// if the entity went away, forget it
	if (!client->r.inuse)
		return false;
	if (client == self->enemy)
		return true;	// JDC false;

	noise = strcmp(client->classname, "player_noise") == 0;
	if (!noise && (client->r.svflags & SVF_NOCLIENT))
		return false;

	if (client->r.client)
	{
		if (client->flags & FL_NOTARGET)
			return false;
	}
	else if (client->r.svflags & SVF_MONSTER)
	{
		if (!client->enemy)
			return false;
		if (client->enemy->flags & FL_NOTARGET)
			return false;
	}
	else if (heardit)
	{
		if (client->r.owner->flags & FL_NOTARGET)
			return false;
	}
	else
		return false;

	if (!heardit)
	{
		r = range (self, client);

		if (r == RANGE_FAR)
			return false;

// this is where we would check invisibility

		// is client in an spot too dark to be seen?
//		if (client->light_level <= 5)
//			return false;

		if (!G_Visible (self, client))
		{
			return false;
		}

		if (r == RANGE_NEAR)
		{
			if (client->show_hostile < level.time && !G_InFront (self, client))
			{
				return false;
			}
		}
		else if (r == RANGE_MID)
		{
			if (!G_InFront (self, client))
			{
				return false;
			}
		}

		self->enemy = client;

		if (!noise)
		{
			self->monsterinfo.aiflags &= ~AI_SOUND_TARGET;

			if (!self->enemy->r.client)
			{
				self->enemy = self->enemy->enemy;
				if (!self->enemy->r.client)
				{
					self->enemy = NULL;
					return false;
				}
			}
		}
	}
	else	// heardit
	{
		vec3_t	temp;

		if (self->spawnflags & 1)
		{
			if (!G_Visible (self, client))
				return false;
		}

		VectorSubtract (client->s.origin, self->s.origin, temp);

		if (VectorLength(temp) > 1000)	// too far to hear
		{
			return false;
		}

		// check area portals - if they are different and not connected then we can't hear it
		if (client->r.areanum != self->r.areanum)
			if (!trap_CM_AreasConnected(self->r.areanum, client->r.areanum))
				return false;

		self->ideal_yaw = vectoyaw(temp);
		M_ChangeYaw (self);

		// hunt the sound for a bit; hopefully find the real player
		self->monsterinfo.aiflags |= AI_SOUND_TARGET;
		self->enemy = client;
	}

//
// got one
//
	FoundTarget (self);

	if (!(self->monsterinfo.aiflags & AI_SOUND_TARGET) && (self->monsterinfo.sight))
		self->monsterinfo.sight (self, self->enemy);

	return true;
}