Jump to content

A fix for stupid AI?


Recommended Posts

I'm wondering -- especially with the JK source code loose now -- whether anyone has managed to fix the undeniably stupid jumping and back-and-forth running behaviour of added bot characters in Multiplayer JKA? Or is this a limitation of the Quake 3 engine? (Don't say it is if you're not sure!)

 

If you're uncertain what I mean, try loading Darth Vader as a computer opponent in Multiplayer, and see him bouncing like a four-year-old.

 

Can they be made to be grounded and attack methodically?

Link to comment

This is what they do when they don't have a bot route for the map.

 

But even with the bot route, they often end up running back and forth in what appears to be without method.

 

Would there be any way to change this default behaviour to a more stationary/composed one? I can't see jumping around benefiting anything, and I think it's a major mess-up on the part of the original development team.

Link to comment

Although, thinking about it, this does sound like a limitation to the engine itself. If it requires scripted bot routes to define behaviour for computer controlled characters and relies on these scripted routes to the full extent, then there really is limited/minimal AI scripting support in the game.

 

Can anyone with extensive knowledge confirm that the engine relies on the bot routes 100% to define the behaviour/movement of bots in-game? I haven't looked at the source code myself...

Link to comment

Although, thinking about it, this does sound like a limitation to the engine itself. If it requires scripted bot routes to define behaviour for computer controlled characters and relies on these scripted routes to the full extent, then there really is limited/minimal AI scripting support in the game.

 

Can anyone with extensive knowledge confirm that the engine relies on the bot routes 100% to define the behaviour/movement of bots in-game? I haven't looked at the source code myself...

Pretty much yes it does.  Otherwise you get stupid jumping behavior.  The single-player npc ai is much better in many cases, but yeah the bots depend on boute routes.

JKG Developer

Link to comment

Pretty much yes it does.  Otherwise you get stupid jumping behavior.  The single-player npc ai is much better in many cases, but yeah the bots depend on boute routes.

 

But the question is how much. Are the routes there for guidance, or are they a set path the bots will always follow that dictates their behaviour? It seems to me there is some programming in place that allows them to make choices independent of the path itself -- like when they encounter the player character as an obstacle.

 

Also, wouldn't forcing the bots to walk instead of run help to stabilise them a bit? Is there any way to force them to walk?

 

I still think something may be done about this to calm their behaviour and make them act more like an opponent in the movies/shows.

Link to comment

has been done in JKG, JKG use a new set of behavior for npcs there use somthing call Autowaypoint system, it fakes npcs to be bots but use npcs AI for its combat, it walks and runs and use all sort of combat skills in it, sad as it is it got pretty broken when it was merge to OJK with a lot of other Stuff, there is a lot of work to get this done if you want npcs to walk, but what i Remember of the AI code, there is some broken behavier in it where it can't find out how to use the button walking and use the pathfinder system to make the npc walks around

Cerez likes this
Link to comment

The problem with improving the AI is that it's one of most difficult areas of development. It's not something that average Joe can go in and fix up properly because there's a lot of maths involved and there's a lot of work to get a good understanding of what needs doing.

Link to comment

The problem with improving the AI is that it's one of most difficult areas of development. It's not something that average Joe can go in and fix up properly because there's a lot of maths involved and there's a lot of work to get a good understanding of what needs doing.

 

Yep, that does figure. Still, I imagine forcing them to walk instead of run wouldn't be too much of a challenge, would it?

Link to comment

Something like that should be pretty easy :P But the decision making is what really needs fixing :/

 

That's true. A core rewrite of the AI system would really benefit this game. But in the meantime, I would personally love to do two things:

 

1. Disable/reduce running for bots.

2. Disable hopping/jumping for bots when no route is present.

 

If anyone knows how to script/modify either of these, please speak up or forever hold your silence. :D

Link to comment

But the question is how much. Are the routes there for guidance, or are they a set path the bots will always follow that dictates their behaviour? It seems to me there is some programming in place that allows them to make choices independent of the path itself -- like when they encounter the player character as an obstacle.

 

Also, wouldn't forcing the bots to walk instead of run help to stabilise them a bit? Is there any way to force them to walk?

 

I still think something may be done about this to calm their behaviour and make them act more like an opponent in the movies/shows.

The paths/routes just provide options to the bots.  Basically it acts as a set of different directions or choices the AI decision tree can make, without a bot route thogh it doesn't have any route to follow, so it just defaults to stupid behavior which involves wandering the level randomly while spamming force jump.  Bots are designed to attack closest enemy available that it encouters along its route; however, if the enemy gets too far away from it, it will ignore the enemy and just continue down the bot route it has chosen.  Forcing bots to walk would simply make them extremely easy to kill, I think this was designed that way on purpose so it wouldn't be so easy to kill them. 

 

Like Xycaleth says though, the npc/bot ai code needs a workover, but that's a massive undertaking that will require someone with motivationandl lots of time and experience with AI coding.

Cerez likes this

JKG Developer

Link to comment

The bot AI is specific to JK2/JKA.  Q3 uses AAS files instead of bot routes with waypoints.  The NPC code and the bot code are two completely separate beasts.

 

The bots will only take the routes of the waypoints.  If they get off course they just jump spam hoping to get back on course if stuck or whatever.

 

See:

int BotFallbackNavigation(bot_state_t *bs)
Cerez likes this
Link to comment

 

The bot AI is specific to JK2/JKA.  Q3 uses AAS files instead of bot routes with waypoints.  The NPC code and the bot code are two completely separate beasts.

 

The bots will only take the routes of the waypoints.  If they get off course they just jump spam hoping to get back on course if stuck or whatever.

 

See:

int BotFallbackNavigation(bot_state_t *bs)

 

LOL, go Raven Software! How can you design AI based on a fixed route where the actual AI is reduced to guess-finding a route and attacking an enemy in range if the enemy happens to be near the designated path. As good as many features of JKA are, this is one of the worst.

 

I'm guessing that the funds for this were cut to bare-bone low because the management thought MP will be just a gimmick, and isn't worth investing much in.

 

Thanks for the insight, Ensiform. I suppose the only way to really fix this would be to code a new AI system, or adapt the NPC system for MP. I'm guessing the latter is what the JKG and OpenJK team are working on.

 

Oh, and thanks for the detailed explanation, Darth. I appreciate it.

Link to comment

Nope.  What would give you the idea that OpenJK is using JKG-specific stuff?

 

See above comments from fellow members. I take it that's not the case, then. It doesn't matter, really. Either way this is way too big a task to take lightly, and will need much dedication to be improved/fixed.

Link to comment

I see. But I take it some of the code related to this has been brought over from JKG?

OpenJK's main goal is to provide compatibility / bug fix JKA.  This is more of a feature, as a result it doesn't really belong in OpenJK.  Also JKG's stuff was for npcs, not bots.  JKG was never designed or intended to really have/support bots and as a result we've done very little to nothing with the existing bot code.

JKG Developer

Link to comment

OpenJK's main goal is to provide compatibility / bug fix JKA.  This is more of a feature, as a result it doesn't really belong in OpenJK.  Also JKG's stuff was for npcs, not bots.  JKG was never designed or intended to really have/support bots and as a result we've done very little to nothing with the existing bot code.

 

I see. Thank for the heads-up, Darth. This helps to clarify the general direction of the two projects better.

Link to comment

Making Bots walk.

 

A bot will normally run everywhere .However ,normally a bot with a blaster will select saber if you get close to him , to engage in saber combat.

 

Add this code and a bot with a saber will walk when he gets close enough to you,but bots with guns only will keep running so the are harder to shoot at.



/*
==============
BotInputToUserCommand
==============
*/
void BotInputToUserCommand(bot_input_t *bi, usercmd_t *ucmd, int delta_angles[3], int time, int useTime)
{
	vec3_t angles, forward, right;
	short temp;
	int j;
	float f, r, u, m;

	//clear the whole structure
	memset(ucmd, 0, sizeof(usercmd_t));
	//the duration for the user command in milli seconds
	ucmd->serverTime = time;
	//
	if (bi->actionflags & ACTION_DELAYEDJUMP)
	{
		bi->actionflags |= ACTION_JUMP;
		bi->actionflags &= ~ACTION_DELAYEDJUMP;
	}
	//set the buttons
	if (bi->actionflags & ACTION_RESPAWN) ucmd->buttons = BUTTON_ATTACK;
	if (bi->actionflags & ACTION_ATTACK) ucmd->buttons |= BUTTON_ATTACK;
	if (bi->actionflags & ACTION_ALT_ATTACK) ucmd->buttons |= BUTTON_ALT_ATTACK;
	if (bi->actionflags & ACTION_SABERTHROW) ucmd->buttons |= BUTTON_SABERTHROW;
	if (bi->actionflags & ACTION_GESTURE) ucmd->buttons |= BUTTON_GESTURE;
	if (bi->actionflags & ACTION_USE) ucmd->buttons |= BUTTON_USE_HOLDABLE;
	if (bi->actionflags & ACTION_WALK) ucmd->buttons |= BUTTON_WALKING;

	if(bi->weapon == WP_SABER)
	{
		if (bi->actionflags & ACTION_FORCEPOWER) ucmd->buttons |= BUTTON_ATTACK;
	}
	else
	{
		if (bi->actionflags & ACTION_FORCEPOWER) ucmd->buttons |= BUTTON_FORCEPOWER;
	}
	//RAFIXME:  This is a hack to fix the hack that Raven did
	if (bi->actionflags & ACTION_USE) ucmd->buttons |= BUTTON_USE;

	if (useTime < level.time && Q_irand(1, 10) < 5)
	{ //for now just hit use randomly in case there's something useable around
		ucmd->buttons |= BUTTON_USE;
	}

	if (bi->weapon == WP_NONE)
	{
		bi->weapon = WP_BRYAR_PISTOL;
	}

	//
	ucmd->weapon = bi->weapon;
	//set the view angles
	//NOTE: the ucmd->angles are the angles WITHOUT the delta angles
	ucmd->angles[PITCH] = ANGLE2SHORT(bi->viewangles[PITCH]);
	ucmd->angles[YAW] = ANGLE2SHORT(bi->viewangles[YAW]);
	ucmd->angles[ROLL] = ANGLE2SHORT(bi->viewangles[ROLL]);
	//subtract the delta angles
	for (j = 0; j < 3; j++) 
	{
		temp = ucmd->angles[j] - delta_angles[j];
		ucmd->angles[j] = temp;
	}
	//NOTE: movement is relative to the REAL view angles
	//get the horizontal forward and right vector
	//get the pitch in the range [-180, 180]
	if (bi->dir[2]) angles[PITCH] = bi->viewangles[PITCH];
	else angles[PITCH] = 0;
	angles[YAW] = bi->viewangles[YAW];
	angles[ROLL] = 0;
	AngleVectors(angles, forward, right, NULL);
	//bot input speed is in the range [0, 400]
	bi->speed = bi->speed * 127 / 400;
	//set the view independent movement
	f = DotProduct(forward, bi->dir);
	r = DotProduct(right, bi->dir);
	u = abs(forward[2]) * bi->dir[2];
	m = fabs(f);

	if (fabs(r) > m)
	{
		m = fabs(r);
	}

	if (fabs(u) > m)
	{
		m = fabs(u);
	}

	if (m > 0)
	{
		f *= bi->speed / m;
		r *= bi->speed / m;
		u *= bi->speed / m;
	}

	ucmd->forwardmove = f;
	ucmd->rightmove = r;
	ucmd->upmove = u;
	//normal keyboard movement
	if (bi->actionflags & ACTION_MOVEFORWARD) ucmd->forwardmove = 127;
	if (bi->actionflags & ACTION_MOVEBACK) ucmd->forwardmove = -127;
	if (bi->actionflags & ACTION_MOVELEFT) ucmd->rightmove = -127;
	if (bi->actionflags & ACTION_MOVERIGHT) ucmd->rightmove = 127;
	//jump/moveup
	if (bi->actionflags & ACTION_JUMP) ucmd->upmove = 127;
	//crouch/movedown
	if (bi->actionflags & ACTION_CROUCH) ucmd->upmove = -127;

	//Make walking work for bots.
	if (bi->actionflags & ACTION_WALK)
	{
		if (ucmd->forwardmove > 46)
		{
			ucmd->forwardmove = 46;	
		}
		else if (ucmd->forwardmove < -46)
		{
			ucmd->forwardmove = -46;
		}
		
		if (ucmd->rightmove > 46)
		{
			ucmd->rightmove = 46;
		}
		else if ( ucmd->rightmove < -46)
		{
			ucmd->rightmove = -46;
		}
	}
	//fixed problem with a bot's force power select not being treating properly by the pm code.
	ucmd->forcesel = bi->forcesel;
}

/*
==============
BotUpdateInput
==============
*/
int		walktime[MAX_CLIENTS];	//timer for walking
extern qboolean visible (gentity_t *self, gentity_t *other);

void BotUpdateInput(bot_state_t *bs, int time, int elapsed_time)
{
	bot_input_t bi;
	int j;

	//add the delta angles to the bot's current view angles
	for (j = 0; j < 3; j++)
	{
		bs->viewangles[j] = AngleMod(bs->viewangles[j] + SHORT2ANGLE(bs->cur_ps.delta_angles[j]));
	}
	// bot view angles
         BotChangeViewAngles(bs, (float) elapsed_time / 1000);

	//retrieve the bot input
	trap_EA_GetInput(bs->client, (float) time / 1000, &bi);
	//respawn hack
	if (bi.actionflags & ACTION_RESPAWN) 
	{
		if (bs->lastucmd.buttons & BUTTON_ATTACK) bi.actionflags &= ~(ACTION_RESPAWN|ACTION_ATTACK);
	}

	if(bs->cur_ps.weapon == WP_SABER)
	{
		if ( bs->currentEnemy 
			&& bs->currentEnemy->client
			&& bs->currentEnemy->health > 0
			&& bs->jumpTime <= level.time // Don't walk during jumping...
			&& (VectorDistance(g_entities[bs->cur_ps.clientNum].r.currentOrigin, bs->currentEnemy->r.currentOrigin) < 150 || walktime[bs->cur_ps.clientNum] > level.time) )
		{
			if ( visible(&g_entities[bs->cur_ps.clientNum], bs->currentEnemy) || walktime[bs->cur_ps.clientNum] > level.time )
			{// Make bots with an enemy walk...
				bi.actionflags |= ACTION_WALK;
				walktime[bs->cur_ps.clientNum] = level.time + 2000;
			}
			else
			{// Reset.
				walktime[bs->cur_ps.clientNum] = 0;
			}
		}
		else
		{// Reset.
			walktime[bs->cur_ps.clientNum] = 0;
		}
	}

	if (bs->doSaberThrow)
	{
		bi.actionflags |= ACTION_SABERTHROW;
	}
	
	if(1)
	{
		int curmove = g_entities[bs->client].client->ps.saberMove;
		if( PM_SaberInStart( curmove ) || PM_SaberInTransition( curmove ) )
		{
			bi.actionflags |= ACTION_ATTACK;
		}
	}
	if(bs->doWalk && bs->cur_ps.weapon == WP_SABER)
	{
		bi.actionflags |= ACTION_WALK;
	}
	//set up forcesel.  Doesn't use cur_ps, since cur_ps is just a copy of the real ps.
	bi.forcesel = level.clients[bs->client].ps.fd.forcePowerSelected;

	//convert the bot input to a usercmd
	BotInputToUserCommand(&bi, &bs->lastucmd, bs->cur_ps.delta_angles, time, bs->noUseTime);
	//subtract the delta angles
	for (j = 0; j < 3; j++)
	{
		bs->viewangles[j] = AngleMod(bs->viewangles[j] - SHORT2ANGLE(bs->cur_ps.delta_angles[j]));
	}
}

hope this helps.................... :)

Cerez and Futuza like this
Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...