示例#1
0
/*
============
AICast_Sight
============
*/
void AICast_Sight( gentity_t *ent, gentity_t *other, int lastSight ) {
	cast_state_t    *cs, *ocs;

	cs = AICast_GetCastState( ent->s.number );
	ocs = AICast_GetCastState( other->s.number );

	//
	// call the sightfunc for this cast, so we can play associated sounds, or do any character-specific things
	//
	if ( cs->sightfunc ) {
		// factor in the reaction time
		if ( AICast_EntityVisible( cs, other->s.number, qfalse ) ) {
			cs->sightfunc( ent, other, lastSight );
		}
	}

	if ( other->aiName && other->health <= 0 ) {

		// they died since we last saw them
		if ( ocs->deathTime > lastSight ) {
			if ( !AICast_SameTeam( cs, other->s.number ) ) {
				AICast_ScriptEvent( cs, "enemysightcorpse", other->aiName );
			} else if ( !( cs->castScriptStatus.scriptFlags & SFL_FRIENDLYSIGHTCORPSE_TRIGGERED ) ) {
				cs->castScriptStatus.scriptFlags |= SFL_FRIENDLYSIGHTCORPSE_TRIGGERED;
				AICast_ScriptEvent( cs, "friendlysightcorpse", "" );
			}
		}

		// if this is the first time, call the sight script event
	} else if ( !lastSight && other->aiName ) {
		if ( !AICast_SameTeam( cs, other->s.number ) ) {
			// disabled.. triggered when entering combat mode
			//AICast_ScriptEvent( cs, "enemysight", other->aiName );
		} else {
			AICast_ScriptEvent( cs, "sight", other->aiName );
		}
	}
}
示例#2
0
void AICast_SightUpdate( int numchecks ) {
	int count = 0, destcount, srccount;
	int src, dest;
	gentity_t       *srcent, *destent;
	cast_state_t    *cs, *dcs;
	//static int	lastNumUpdated; // TTimo: unused
	cast_visibility_t *vis;
	#define SIGHT_MIN_DELAY 200

	src = 0;
	dest = 0;
	if ( numchecks < 5 ) {
		numchecks = 5;
	}

	if ( trap_Cvar_VariableIntegerValue( "savegame_loading" ) ) {
		return;
	}

	if ( saveGamePending ) {
		return;
	}

	// First, check all REAL clients, so sighting player is only effected by reaction_time, not
	// effected by framerate also
	for (   srccount = 0, src = 0, srcent = &g_entities[0];
			src < aicast_maxclients && srccount < level.numPlayingClients;
			src++, srcent++ )
	{
		if ( !srcent->inuse ) {
			continue;
		}

		srccount++;

		if ( srcent->aiInactive ) {
			continue;
		}
		if ( srcent->health <= 0 ) {
			continue;
		}
		if ( !( srcent->r.svFlags & SVF_CASTAI ) ) { // only source check AI Cast
			continue;
		}

		cs = AICast_GetCastState( src );

		if ( cs->castScriptStatus.scriptNoSightTime >= level.time ) {
			continue;
		}

		// make sure we are using the right AAS data for this entity (one's that don't get set will default to the player's AAS data)
		trap_AAS_SetCurrentWorld( cs->aasWorldIndex );

		for (   destcount = 0, dest = 0, destent = g_entities;
				//dest < aicast_maxclients && destcount < level.numPlayingClients;
				destent == g_entities;  // only check the player
				dest++, destent++ )
		{
			if ( !destent->inuse ) {
				continue;
			}

			destcount++;

			if ( destent->health <= 0 ) {
				continue;
			}
			if ( destent->r.svFlags & SVF_CASTAI ) {      // only dest check REAL clients
				continue;
			}

			if ( src == dest ) {
				continue;
			}

			vis = &cs->vislist[destent->s.number];

			// OPTIMIZATION: if we have seen the player, abort checking each frame
			//if (vis->real_visible_timestamp && cs->aiState > AISTATE_QUERY && AICast_HostileEnemy(cs, destent->s.number))
			//	continue;

			// if we saw them last frame, skip this test, so we only check initial sightings each frame
			if ( vis->lastcheck_timestamp == vis->real_visible_timestamp ) {
				continue;
			}

			// if we recently checked this vis, skip
			if ( vis->lastcheck_timestamp >= level.time - ( 40 + rand() % 40 ) ) {
				continue;
			}

			// check for visibility
			if (    !( destent->flags & FL_NOTARGET )
					&&  ( AICast_CheckVisibility( srcent, destent ) ) ) {
				// record the sighting
				AICast_UpdateVisibility( srcent, destent, qtrue, qtrue );
			} else // if (vis->lastcheck_timestamp == vis->real_update_timestamp)
			{
				AICast_UpdateNonVisibility( srcent, destent, qtrue );
			}
		}
	}

	// Now do the normal timeslice checks
	for (   srccount = 0, src = lastsrc, srcent = &g_entities[lastsrc];
			src < aicast_maxclients; // && srccount < level.numPlayingClients;
			src++, srcent++ )
	{
		if ( !srcent->inuse ) {
			continue;
		}

		srccount++;

		if ( srcent->aiInactive ) {
			continue;
		}
		if ( srcent->health <= 0 ) {
			continue;
		}

		cs = AICast_GetCastState( src );

		if ( cs->castScriptStatus.scriptNoSightTime >= level.time ) {
			continue;
		}

		// make sure we are using the right AAS data for this entity (one's that don't get set will default to the player's AAS data)
		trap_AAS_SetCurrentWorld( cs->aasWorldIndex );

		if ( lastdest < 0 ) {
			lastdest = 0;
		}

		for (   destcount = 0, dest = lastdest, destent = &g_entities[lastdest];
				dest < aicast_maxclients; // && destcount < level.numPlayingClients;
				dest++, destent++ )
		{
			if ( !destent->inuse ) {
				continue;
			}

			destcount++;

			if ( destent->aiInactive ) {
				continue;
			}
			if ( src == dest ) {
				continue;
			}

			dcs = AICast_GetCastState( destent->s.number );

			vis = &cs->vislist[destent->s.number];

			// don't check too often
			if ( vis->lastcheck_timestamp > ( level.time - SIGHT_MIN_DELAY ) ) {
				continue;
			}

			if ( destent->health <= 0 ) {
				// only check dead guys until they are sighted
				if ( vis->lastcheck_health < 0 ) {
					continue;
				}
			}

			if ( vis->lastcheck_timestamp > level.time ) {
				continue;   // let the loadgame settle down

			}
			// if they are friends, only check very infrequently
			if ( AICast_SameTeam( cs, destent->s.number ) && ( vis->lastcheck_timestamp == vis->visible_timestamp )
				 &&  ( destent->health == vis->lastcheck_health + 1 ) ) {
				if ( dcs->aiState < AISTATE_COMBAT ) {
					if ( vis->lastcheck_timestamp > ( level.time - ( 2000 + rand() % 1000 ) ) ) {
						continue;   // dont check too often
					}
				} else {    // check a little more frequently
					if ( vis->lastcheck_timestamp > ( level.time - ( 500 + rand() % 500 ) ) ) {
						continue;   // dont check too often
					}
				}
			}

			// check for visibility
			if (    !( destent->flags & FL_NOTARGET )
					&&  ( AICast_CheckVisibility( srcent, destent ) ) ) {
				// make sure they are still with us
				if ( destent->inuse ) {
					// record the sighting
					AICast_UpdateVisibility( srcent, destent, qtrue, qtrue );
				}
			} else // if (vis->lastcheck_timestamp == vis->real_update_timestamp)
			{
				AICast_UpdateNonVisibility( srcent, destent, qtrue );
			}

			// break if we've processed the maximum visibilities
			if ( ++count > numchecks ) {
				dest++;
				if ( dest >= aicast_maxclients ) {
					src++;
				}
				goto escape;
			}
		}

		lastdest = 0;
	}

escape:

	if ( src >= aicast_maxclients ) {
		src = 0;
	}
	lastsrc = src;
	if ( dest >= aicast_maxclients ) {
		dest = 0;
	}
	lastdest = dest;
}
示例#3
0
/*
============
AICast_ProcessActivate
============
*/
void AICast_ProcessActivate( int entNum, int activatorNum ) {
	cast_state_t *cs;
	gentity_t *newent, *ent, *activator;
	gclient_t *client;

	cs = AICast_GetCastState( entNum );
	client = &level.clients[entNum];
	ent = &g_entities[entNum];
	activator = &g_entities[activatorNum];

	if ( !AICast_SameTeam( cs, activatorNum ) ) {

		if ( ent->aiTeam == AITEAM_NEUTRAL ) {
			AICast_ScriptEvent( cs, "activate", g_entities[activatorNum].aiName );
		}

		return;
	}

	// try running the activate event, if it denies us the request, then abort
	cs->aiFlags &= ~AIFL_DENYACTION;
	AICast_ScriptEvent( cs, "activate", g_entities[activatorNum].aiName );
	if ( cs->aiFlags & AIFL_DENYACTION ) {
		return;
	}

	// if we are doing something else
	if ( cs->castScriptStatus.castScriptEventIndex >= 0 ) {
		if ( ent->eventTime != level.time ) {
			G_AddEvent( &g_entities[entNum], EV_GENERAL_SOUND, G_SoundIndex( aiDefaults[cs->aiCharacter].ordersDenySoundScript ) );
		}
		return;
	}

	// if we are already following them, stop following
	if ( cs->leaderNum == activatorNum ) {
		if ( ent->eventTime != level.time ) {
			G_AddEvent( &g_entities[entNum], EV_GENERAL_SOUND, G_SoundIndex( aiDefaults[cs->aiCharacter].staySoundScript ) );
		}

		cs->leaderNum = -1;

		// create a goal at this position
		newent = G_Spawn();
		newent->classname = "AI_wait_goal";
		newent->r.ownerNum = entNum;
		G_SetOrigin( newent, cs->bs->origin );
		AIFunc_ChaseGoalStart( cs, newent->s.number, 128, qtrue );

		//AIFunc_IdleStart( cs );
	} else {    // start following
		int count, i;
		cast_state_t *tcs;

		// if they already have enough followers, deny
		for ( count = 0, i = 0, tcs = caststates; i < level.maxclients; i++, tcs++ ) {
			if ( tcs->bs && tcs != cs && tcs->entityNum != activatorNum && g_entities[tcs->entityNum].health > 0 && tcs->leaderNum == activatorNum ) {
				count++;
			}
		}
		if ( count >= 3 ) {
			if ( ent->eventTime != level.time ) {
				G_AddEvent( &g_entities[entNum], EV_GENERAL_SOUND, G_SoundIndex( aiDefaults[cs->aiCharacter].ordersDenySoundScript ) );
			}
			return;
		}

		if ( ent->eventTime != level.time ) {
			G_AddEvent( &g_entities[entNum], EV_GENERAL_SOUND, G_SoundIndex( aiDefaults[cs->aiCharacter].followSoundScript ) );
		}

		// if they have a wait goal, free it
		if ( cs->followEntity >= MAX_CLIENTS && g_entities[cs->followEntity].classname && !strcmp( g_entities[cs->followEntity].classname, "AI_wait_goal" ) ) {
			G_FreeEntity( &g_entities[cs->followEntity] );
		}

		cs->followEntity = -1;
		cs->leaderNum = activatorNum;
	}
}
示例#4
0
/*
==============
AICast_UpdateVisibility
==============
*/
void AICast_UpdateVisibility( gentity_t *srcent, gentity_t *destent, qboolean shareVis, qboolean directview ) {
	cast_visibility_t   *vis, *ovis, *svis, oldvis;
	cast_state_t        *cs, *ocs;
	qboolean shareRange;
	int cnt, i;

	if ( destent->flags & FL_NOTARGET ) {
		return;
	}

	cs = AICast_GetCastState( srcent->s.number );
	ocs = AICast_GetCastState( destent->s.number );

	if ( cs->castScriptStatus.scriptNoSightTime >= level.time ) {
		return;     // absolutely no sight (or hear) information allowed

	}
	shareRange = ( VectorDistance( srcent->client->ps.origin, destent->client->ps.origin ) < AIVIS_SHARE_RANGE );

	vis = &cs->vislist[destent->s.number];

	vis->chase_marker_count = 0;

	if ( aicast_debug.integer == 1 ) {
		if ( !vis->visible_timestamp || vis->visible_timestamp < level.time - 5000 ) {
			if ( directview ) {
				G_Printf( "SIGHT (direct): %s sees %s\n", srcent->aiName, destent->aiName );
			} else {
				G_Printf( "SIGHT (non-direct/audible): %s sees %s\n", srcent->aiName, destent->aiName );
			}
		}
	}

	// trigger the sight event
	AICast_Sight( srcent, destent, vis->visible_timestamp );

	// update the values
	vis->lastcheck_timestamp = level.time;
	vis->visible_timestamp = level.time;
	VectorCopy( destent->client->ps.origin, vis->visible_pos );
	VectorCopy( destent->client->ps.velocity, vis->visible_vel );
	vis->lastcheck_health = destent->health - 1;

	// we may need to process this visibility at some point, even after they become not visible again
	vis->flags |= AIVIS_PROCESS_SIGHTING;

	if ( directview ) {
		vis->real_visible_timestamp = level.time;
		VectorCopy( destent->client->ps.origin, vis->real_visible_pos );
		vis->real_update_timestamp = level.time;
	}

	// if we are on fire, then run away from anything we see
	if ( cs->attributes[AGGRESSION] < 1.0 && srcent->s.onFireEnd > level.time && ( !destent->s.number || cs->dangerEntityValidTime < level.time + 2000 ) && !( cs->aiFlags & AIFL_NO_FLAME_DAMAGE ) ) {
		cs->dangerEntity = destent->s.number;
		VectorCopy( destent->r.currentOrigin, cs->dangerEntityPos );
		cs->dangerEntityValidTime = level.time + 5000;
		cs->dangerDist = 99999;
		cs->dangerEntityTimestamp = level.time;
	}

	// Look for reasons to make this character an enemy of ours

	// if they are an enemy and inside the detection radius, go hostile
	if ( !( vis->flags & AIVIS_ENEMY ) && !AICast_SameTeam( cs, destent->s.number ) ) {
		float idr;

		idr = cs->attributes[INNER_DETECTION_RADIUS];
		if ( cs->aiFlags & AIFL_ZOOMING ) {
			idr *= 10;
		}
		if ( !( vis->flags & AIVIS_ENEMY ) && VectorDistance( vis->visible_pos, g_entities[cs->entityNum].r.currentOrigin ) < idr ) {
			// RF, moved them over to AICast_ScanForEnemies()
			//AICast_ScriptEvent( cs, "enemysight", destent->aiName );
			vis->flags |= AIVIS_ENEMY;
		}
		// if we are in (or above) ALERT mode, then we now know this is an enemy
		else if ( cs->aiState >= AISTATE_ALERT ) {
			// RF, moved them over to AICast_ScanForEnemies()
			//AICast_ScriptEvent( cs, "enemysight", destent->aiName );
			vis->flags |= AIVIS_ENEMY;
		}
	}

	// if they are friendly, then we should help them out if they are in trouble
	if ( AICast_SameTeam( cs, destent->s.number ) && ( srcent->aiTeam == AITEAM_ALLIES || srcent->aiTeam == AITEAM_NAZI ) ) {
		// if they are dead, we should check them out
		if ( destent->health <= 0 ) {
			// if we haven't already checked them out
			if ( !( vis->flags & AIVIS_INSPECTED ) ) {
				vis->flags |= AIVIS_INSPECT;
			}
			// if they are mad, we should help, or at least act concerned
		} else if ( cs->aiState < AISTATE_COMBAT && ocs->aiState >= AISTATE_COMBAT && ocs->bs && ( ocs->enemyNum >= 0 ) ) {
			// if we haven't already checked them out
			if ( !( vis->flags & AIVIS_INSPECTED ) ) {
				vis->flags |= AIVIS_INSPECT;
			}
			// if they are alert, we should also go alert
		} else if ( cs->aiState < AISTATE_ALERT && ocs->aiState == AISTATE_ALERT && ocs->bs ) {
			AICast_StateChange( cs, AISTATE_ALERT );
		}
	}

	// if this is a friendly, then check them for hostile's that we currently haven't upgraded so

	if ( ( destent->health > 0 ) &&
		 ( srcent->aiTeam == destent->aiTeam ) && // only share with exact same team, and non-neutrals
		 ( srcent->aiTeam != AITEAM_NEUTRAL ) ) {
		ocs = AICast_GetCastState( destent->s.number );
		cnt = 0;
		//
		for ( i = 0; i < aicast_maxclients && cnt < level.numPlayingClients; i++ ) {
			if ( !g_entities[i].inuse ) {
				continue;
			}
			//
			cnt++;
			//
			if ( i == srcent->s.number ) {
				continue;
			}
			if ( i == destent->s.number ) {
				continue;
			}
			//
			ovis = &ocs->vislist[i];
			svis = &cs->vislist[i];
			//
			// if we are close to the friendly, then we should share their visibility info
			if ( destent->health > 0 && shareRange ) {
				oldvis = *svis;
				// if they have seen this character more recently than us, share
				if ( ( ovis->visible_timestamp > svis->visible_timestamp ) ||
					 ( ( ovis->visible_timestamp > level.time - 5000 ) && ( ovis->flags & AIVIS_ENEMY ) && !( svis->flags & AIVIS_ENEMY ) ) ) {
					// trigger an EVENT

					// trigger the sight event
					AICast_Sight( srcent, destent, ovis->visible_timestamp );

					// we may need to process this visibility at some point, even after they become not visible again
					svis->flags |= AIVIS_PROCESS_SIGHTING;

					// if we are sharing information about an enemy, then trigger a scripted event
					if ( !svis->real_visible_timestamp && ovis->real_visible_timestamp && ( ovis->flags & AIVIS_ENEMY ) ) {
						// setup conditions
						BG_UpdateConditionValue( ocs->entityNum, ANIM_COND_ENEMY_TEAM, g_entities[i].aiTeam, qfalse );
						// call the event
						BG_AnimScriptEvent( &g_entities[ocs->entityNum].client->ps, ANIM_ET_INFORM_FRIENDLY_OF_ENEMY, qfalse, qfalse );
					}
					// copy the whole structure
					*svis = *ovis;
					// minus the flags
					svis->flags = oldvis.flags;
					// keep our sight time if it's sooner
					if ( oldvis.visible_timestamp > ovis->visible_timestamp ) {
						svis->visible_timestamp = oldvis.visible_timestamp;
					}
					// check to see if we just made this character an enemy of ours
					if ( /*(cs->aiState == AISTATE_COMBAT) &&*/ ( ovis->flags & AIVIS_ENEMY ) && !( oldvis.flags & AIVIS_ENEMY ) ) {
						svis->flags |= AIVIS_ENEMY;
						if ( !( cs->vislist[i].flags & AIVIS_SIGHT_SCRIPT_CALLED ) ) {
							AICast_ScriptEvent( cs, "enemysight", g_entities[i].aiName );
							cs->vislist[i].flags |= AIVIS_SIGHT_SCRIPT_CALLED;
							if ( !( cs->aiFlags & AIFL_DENYACTION ) ) {
								G_AddEvent( srcent, EV_GENERAL_SOUND, G_SoundIndex( aiDefaults[cs->aiCharacter].soundScripts[SIGHTSOUNDSCRIPT] ) );
							}
						}
					}
				}
			} else {
				// if either of us haven't seen this character yet, then ignore it
				if ( !svis->visible_timestamp || !ovis->visible_timestamp ) {
					continue;
				}
			}
			//
			// if they have marked this character as hostile, then we should also
			if ( ( cs->aiState == AISTATE_COMBAT ) && AICast_HostileEnemy( ocs, i ) && !AICast_HostileEnemy( cs, i ) ) {
				if ( !( cs->vislist[i].flags & AIVIS_SIGHT_SCRIPT_CALLED ) ) {
					AICast_ScriptEvent( cs, "enemysight", g_entities[i].aiName );
					cs->vislist[i].flags |= AIVIS_SIGHT_SCRIPT_CALLED;
					if ( !( cs->aiFlags & AIFL_DENYACTION ) ) {
						G_AddEvent( srcent, EV_GENERAL_SOUND, G_SoundIndex( aiDefaults[cs->aiCharacter].soundScripts[SIGHTSOUNDSCRIPT] ) );
					}
				}
				svis->flags |= AIVIS_ENEMY;
			}
		}
	}
}