예제 #1
0
/*
================
G_FindTeams

Chain together all entities with a matching team field.
Entity teams are used for item groups and multi-entity mover groups.

All but the first will have the FL_TEAMSLAVE flag set and teammaster field set
All but the last will have the teamchain field set to the next one
================
*/
void G_FindTeams( void ) {
	gentity_t	*e, *e2;
	int		i, j;
	int		c, c2;

	c = 0;
	c2 = 0;
//	for ( i=1, e=g_entities,i ; i < globals.num_entities ; i++,e++ )
	for ( i=1 ; i < globals.num_entities ; i++ )
	{
//		if (!e->inuse)
//			continue;
		if(!PInUse(i))
			continue;
		e=&g_entities[i];

		if (!e->team)
			continue;
		if (e->flags & FL_TEAMSLAVE)
			continue;
		e->teammaster = e;
		c++;
		c2++;
//		for (j=i+1, e2=e+1 ; j < globals.num_entities ; j++,e2++)
		for (j=i+1; j < globals.num_entities ; j++)
		{
//			if (!e2->inuse)
//				continue;
			if(!PInUse(j))
				continue;
			
			e2=&g_entities[j];
			if (!e2->team)
				continue;
			if (e2->flags & FL_TEAMSLAVE)
				continue;
			if (!strcmp(e->team, e2->team))
			{
				c2++;
				e2->teamchain = e->teamchain;
				e->teamchain = e2;
				e2->teammaster = e;
				e2->flags |= FL_TEAMSLAVE;

				// make sure that targets only point at the master
				if ( e2->targetname ) {
					e->targetname = e2->targetname;
					e2->targetname = NULL;
				}
			}
		}
	}

	gi.Printf ("%i teams with %i entities\n", c, c2);
}
예제 #2
0
void ValidateInUseBits(void)
{
	for(int i=0;i<MAX_GENTITIES;i++)
	{
		assert(g_entities[i].inuse==PInUse(i));
	}
}
예제 #3
0
파일: g_utils.cpp 프로젝트: kikili/OpenJK
/*
=============
G_Find

Searches all active entities for the next one that holds
the matching string at fieldofs (use the FOFS() macro) in the structure.

Searches beginning at the entity after from, or the beginning if NULL
NULL will be returned if the end of the list is reached.

=============
*/
gentity_t *G_Find (gentity_t *from, int fieldofs, const char *match)
{
	char	*s;
	
	if(!match || !match[0])
	{
		return NULL;
	}

	if (!from)
		from = g_entities;
	else
		from++;

//	for ( ; from < &g_entities[globals.num_entities] ; from++)
	int i=from-g_entities;
	for ( ; i < globals.num_entities ; i++)
	{
//		if (!from->inuse)	
		if(!PInUse(i))
			continue;

		from=&g_entities[i];
		s = *(char **) ((byte *)from + fieldofs);
		if (!s)
			continue;
		if (!Q_stricmp (s, match))
			return from;
	}

	return NULL;
}
예제 #4
0
void ReadInUseBits(void)
{
	gi.ReadFromSaveGame('INUS', &g_entityInUseBits, sizeof(g_entityInUseBits));
	// This is only temporary. Once I have converted all the ent->inuse refs,
	// it won;t be needed -MW.
	for(int i=0;i<MAX_GENTITIES;i++)
	{
		g_entities[i].inuse=PInUse(i);
	}
}
예제 #5
0
void ReadInUseBits()
{
	ojk::SavedGameHelper saved_game(
		::gi.saved_game);

	saved_game.read_chunk<uint32_t>(
		INT_ID('I', 'N', 'U', 'S'),
		::g_entityInUseBits);

	// This is only temporary. Once I have converted all the ent->inuse refs,
	// it won;t be needed -MW.
	for(int i=0;i<MAX_GENTITIES;i++)
	{
		g_entities[i].inuse=PInUse(i);
	}
}
예제 #6
0
파일: g_cmds.cpp 프로젝트: PJayB/jk2src
/*
==================
Cmd_Where_f
==================
*/
void Cmd_Where_f( gentity_t *ent ) {
	const char *s = gi.argv(1);
	const int len = strlen(s);
	gentity_t	*check;
	
	if ( gi.argc () < 2 ) {
		gi.Printf("usage: where classname\n");
		return;
	}
	for (int i = 0; i < globals.num_entities; i++)
	{
		if(!PInUse(i))
			continue;
//		if(!check || !check->inuse) {
//			continue;
//		}
		check = &g_entities[i];
		if (!Q_stricmpn(s, check->classname, len) ) {
			gi.SendServerCommand( ent-g_entities, "print \"%s %s\n\"", check->classname, vtos( check->s.pos.trBase ) );
		}
	}
}
예제 #7
0
파일: AI_Utils.cpp 프로젝트: Arbixal/OpenJK
//#define MAX_WAITERS	128
void AI_GetGroup( gentity_t *self )
{
	int	i;
	gentity_t	*member;//, *waiter;
	//int	waiters[MAX_WAITERS];

	if ( !self || !self->NPC )
	{
		return;
	}

	if ( d_noGroupAI->integer )
	{
		self->NPC->group = NULL;
		return;
	}

	if ( !self->client )
	{
		self->NPC->group = NULL;
		return;
	}

	if ( self->NPC->scriptFlags&SCF_NO_GROUPS )
	{
		self->NPC->group = NULL;
		return;
	}

	if ( self->enemy && (!self->enemy->client || (level.time - self->NPC->enemyLastSeenTime > 7000 )))
	{
		self->NPC->group = NULL;
		return;
	}

	if ( !AI_GetNextEmptyGroup( self ) )
	{//either no more groups left or we're already in a group built earlier
		return;
	}

	//create a new one
	memset( self->NPC->group, 0, sizeof( AIGroupInfo_t ) );

	self->NPC->group->enemy = self->enemy;
	self->NPC->group->team = self->client->playerTeam;
	self->NPC->group->processed = qfalse;
	self->NPC->group->commander = self;
	self->NPC->group->memberValidateTime = level.time + 2000;
	self->NPC->group->activeMemberNum = 0;

	if ( self->NPC->group->enemy )
	{
		self->NPC->group->lastSeenEnemyTime = level.time;
		self->NPC->group->lastClearShotTime = level.time;
		VectorCopy( self->NPC->group->enemy->currentOrigin, self->NPC->group->enemyLastSeenPos );
	}

//	for ( i = 0, member = &g_entities[0]; i < globals.num_entities ; i++, member++)
	for ( i = 0; i < globals.num_entities ; i++)
	{
		if(!PInUse(i))
			continue;
		member = &g_entities[i];

		if ( !AI_ValidateGroupMember( self->NPC->group, member ) )
		{//FIXME: keep track of those who aren't angry yet and see if we should wake them after we assemble the core group
			continue;
		}
		
		//store it
		AI_InsertGroupMember( self->NPC->group, member );

		if ( self->NPC->group->numGroup >= (MAX_GROUP_MEMBERS - 1) )
		{//full
			break;
		}
	}

	/*
	//now go through waiters and see if any should join the group
	//NOTE:  Some should hang back and probably not attack, so we can ambush
	//NOTE: only do this if calling for reinforcements?
	for ( i = 0; i < numWaiters; i++ )
	{
		waiter = &g_entities[waiters[i]];
	
		for ( j = 0; j < self->NPC->group->numGroup; j++ )
		{
			member = &g_entities[self->NPC->group->member[j];

			if ( gi.inPVS( waiter->currentOrigin, member->currentOrigin ) )
			{//this waiter is within PVS of a current member
			}
		}
	}
	*/

	if ( self->NPC->group->numGroup <= 0 )
	{//none in group
		self->NPC->group = NULL;
		return;
	}

	AI_SortGroupByPathCostToEnemy( self->NPC->group );
	AI_SetClosestBuddy( self->NPC->group );
}
예제 #8
0
void G_RunFrame( int levelTime ) {
	int			i;
	gentity_t	*ent;
	int			msec;
	int			ents_inuse=0; // someone's gonna be pissed I put this here...
#if	AI_TIMERS
	AITime = 0;
	navTime = 0;
#endif//	AI_TIMERS
	
	level.framenum++;
	level.previousTime = level.time;
	level.time = levelTime;
	msec = level.time - level.previousTime;
	
	NAV_CheckCalcPaths();
	//ResetTeamCounters();
	
	AI_UpdateGroups();

	if ( d_altRoutes->integer )
	{
		navigator.CheckAllFailedEdges();
	}
	navigator.ClearCheckedNodes();

	//remember last waypoint, clear current one
//	for ( i = 0, ent = &g_entities[0]; i < globals.num_entities ; i++, ent++) 
	for ( i = 0; i < globals.num_entities ; i++) 
	{
//		if ( !ent->inuse )
//			continue;

		if(!PInUse(i))
			continue;
		
		ent = &g_entities[i];
	
		if ( ent->waypoint != WAYPOINT_NONE 
			&& ent->noWaypointTime < level.time )
		{
			ent->lastWaypoint = ent->waypoint;
			ent->waypoint = WAYPOINT_NONE;
		}
		if ( d_altRoutes->integer )
		{
			navigator.CheckFailedNodes( ent );
		}
	}

	//Look to clear out old events
	ClearPlayerAlertEvents();

	//Run the frame for all entities
//	for ( i = 0, ent = &g_entities[0]; i < globals.num_entities ; i++, ent++)
	for ( i = 0; i < globals.num_entities ; i++) 
	{
//		if ( !ent->inuse )
//			continue;

		if(!PInUse(i))
			continue;
		ents_inuse++;
		ent = &g_entities[i];

		// clear events that are too old
		if ( level.time - ent->eventTime > EVENT_VALID_MSEC ) {
			if ( ent->s.event ) {
				ent->s.event = 0;	// &= EV_EVENT_BITS;
				if ( ent->client ) {
					ent->client->ps.externalEvent = 0;
				}
			}
			if ( ent->freeAfterEvent ) {
				// tempEntities or dropped items completely go away after their event
				G_FreeEntity( ent );
				continue;
			} else if ( ent->unlinkAfterEvent ) {
				// items that will respawn will hide themselves after their pickup event
				ent->unlinkAfterEvent = qfalse;
				gi.unlinkentity( ent );
			}
		}

		// temporary entities don't think
		if ( ent->freeAfterEvent )
			continue;

		G_CheckTasksCompleted(ent);

		G_Roff( ent );

		if( !ent->client )
		{
			if ( !(ent->svFlags & SVF_SELF_ANIMATING) )
			{//FIXME: make sure this is done only for models with frames?
				//Or just flag as animating?
				if ( ent->s.eFlags & EF_ANIM_ONCE )
				{
					ent->s.frame++;
				}
				else if ( !(ent->s.eFlags & EF_ANIM_ALLFAST) )
				{
					G_Animate( ent );
				}
			}
		}
		G_CheckSpecialPersistentEvents( ent );

		if ( ent->s.eType == ET_MISSILE ) 
		{
			G_RunMissile( ent );
			continue;
		}

		if ( ent->s.eType == ET_ITEM ) 
		{
			G_RunItem( ent );
			continue;
		}

		if ( ent->s.eType == ET_MOVER ) 
		{
			if ( ent->model && Q_stricmp( "models/test/mikeg/tie_fighter.md3", ent->model ) == 0 )
			{
				TieFighterThink( ent );
			}
			G_RunMover( ent );
			continue;
		}

		//The player
		if ( i == 0 ) 
		{
			// decay batteries if the goggles are active
			if ( cg.zoomMode == 1 && ent->client->ps.batteryCharge > 0 )
			{
				ent->client->ps.batteryCharge--;
			}
			else if ( cg.zoomMode == 3 && ent->client->ps.batteryCharge > 0 )
			{
				ent->client->ps.batteryCharge -= 2;

				if ( ent->client->ps.batteryCharge < 0 )
				{
					ent->client->ps.batteryCharge = 0;
				}
			}

			G_CheckEndLevelTimers( ent );
			//Recalculate the nearest waypoint for the coming NPC updates
			NAV_FindPlayerWaypoint();

			if( ent->taskManager && !stop_icarus )
			{
				ent->taskManager->Update();
			}
			//dead
			if ( ent->health <= 0 )
			{
				if ( ent->client->ps.groundEntityNum != ENTITYNUM_NONE )
				{//on the ground
					pitch_roll_for_slope( ent, NULL );
				}
			}

			continue;	// players are ucmd driven
		}

		G_RunThink( ent );	// be aware that ent may be free after returning from here, at least one func frees them
		ClearNPCGlobals();			//	but these 2 funcs are ok
		//UpdateTeamCounters( ent );	//	   to call anyway on a freed ent.
	}

	// perform final fixups on the player
	ent = &g_entities[0];
	if ( ent->inuse ) 
	{
		ClientEndFrame( ent );
	}
	if( g_numEntities->integer )
	{
		gi.Printf( S_COLOR_WHITE"Number of Entities in use : %d\n", ents_inuse );
	}
	//DEBUG STUFF
	NAV_ShowDebugInfo();
	NPC_ShowDebugInfo();

	G_DynamicMusicUpdate();

#if	AI_TIMERS
	AITime -= navTime;
	if ( AITime > 20 )
	{
		gi.Printf( S_COLOR_RED"ERROR: total AI time: %d\n", AITime );
	}
	else if ( AITime > 10 )
	{
		gi.Printf( S_COLOR_YELLOW"WARNING: total AI time: %d\n", AITime );
	}
	else if ( AITime > 2 )
	{
		gi.Printf( S_COLOR_GREEN"total AI time: %d\n", AITime );
	}
	if ( navTime > 20 )
	{
		gi.Printf( S_COLOR_RED"ERROR: total nav time: %d\n", navTime );
	}
	else if ( navTime > 10 )
	{
		gi.Printf( S_COLOR_YELLOW"WARNING: total nav time: %d\n", navTime );
	}
	else if ( navTime > 2 )
	{
		gi.Printf( S_COLOR_GREEN"total nav time: %d\n", navTime );
	}
#endif//	AI_TIMERS

#ifndef FINAL_BUILD
	if ( delayedShutDown != 0 && delayedShutDown < level.time )
	{
		G_Error( "Game Errors. Scroll up the console to read them.\n" );
	}
#endif

#ifdef _DEBUG
	if(!(level.framenum&0xff))
	{
		ValidateInUseBits();
	}
#endif
}
예제 #9
0
파일: g_utils.cpp 프로젝트: kikili/OpenJK
/*
=================
G_Spawn

Either finds a free entity, or allocates a new one.

  The slots from 0 to MAX_CLIENTS-1 are always reserved for clients, and will
never be used by anything else.

Try to avoid reusing an entity that was recently freed, because it
can cause the client to think the entity morphed into something else
instead of being removed and recreated, which can cause interpolated
angles and bad trails.
=================
*/
gentity_t *G_Spawn( void ) 
{
	int			i, force;
	gentity_t	*e;

	e = NULL;	// shut up warning
	i = 0;		// shut up warning
	for ( force = 0 ; force < 2 ; force++ ) 
	{
		// if we go through all entities and can't find one to free,
		// override the normal minimum times before use
		e = &g_entities[MAX_CLIENTS];
//		for ( i = MAX_CLIENTS ; i<globals.num_entities ; i++, e++)
//		{
//			if ( e->inuse )
//			{
//				continue;
//			}
		for ( i = MAX_CLIENTS ; i<globals.num_entities ; i++) 
		{
			if(PInUse(i))
			{
				continue;
			}			
			e=&g_entities[i];

			// the first couple seconds of server time can involve a lot of
			// freeing and allocating, so relax the replacement policy
			if ( !force && e->freetime > 2000 && level.time - e->freetime < 1000 ) {
				continue;
			}

			// reuse this slot
			G_InitGentity( e );
			return e;
		}
		e=&g_entities[i];
		if ( i != ENTITYNUM_MAX_NORMAL )
		{
			break;
		}
	}
	if ( i == ENTITYNUM_MAX_NORMAL )
	{
/*
		e = &g_entities[0];

//--------------Use this to dump directly to a file
		char buff[256];
		FILE *fp;

		fp = fopen( "c:/dump.txt", "w" );
		for ( i = 0 ; i<globals.num_entities ; i++, e++) 
		{
			if ( e->classname )
			{
				sprintf( buff, "%d: %s\n", i, e->classname );
			}

			fputs( buff, fp );
		}
		fclose( fp );
//---------------Or use this to dump to the console -- beware though, the console will fill quickly and you probably won't see the full list
		for ( i = 0 ; i<globals.num_entities ; i++, e++) 
		{
			if ( e->classname )
			{
				Com_Printf( "%d: %s\n", i, e->classname );

			}
		}
*/
		G_Error( "G_Spawn: no free entities" );
	}
	
	// open up a new slot
	globals.num_entities++;
	G_InitGentity( e );
	return e;
}